Merge pull request #1314 from jooola/feat/rework_fixtures
Generate analyzer fixtures
This commit is contained in:
commit
9db31c68ed
|
@ -15,6 +15,7 @@ apt-get install -y gstreamer1.0-plugins-base \
|
|||
liquidsoap-plugin-vorbis \
|
||||
python3-gst-1.0 \
|
||||
silan \
|
||||
ffmpeg \
|
||||
gcc \
|
||||
gir1.2-gtk-3.0 \
|
||||
python3-setuptools \
|
||||
|
|
|
@ -10,7 +10,10 @@ lint:
|
|||
pylint ${MODULE_APP}
|
||||
pylint ${MODULE_TESTS}
|
||||
|
||||
test:
|
||||
fixtures:
|
||||
bash tests/fixtures/generate.sh
|
||||
|
||||
test: fixtures
|
||||
pytest -n ${CPU_CORES} --color=yes -v --cov=${MODULE_APP} ${MODULE_TESTS}
|
||||
|
||||
all: lint test
|
||||
|
|
|
@ -27,7 +27,7 @@ def test_run_analysis(src_dir, dest_dir):
|
|||
assert metadata["year"] == "1999"
|
||||
assert metadata["genre"] == "Test Genre"
|
||||
assert metadata["mime"] == "audio/mp3"
|
||||
assert abs(metadata["length_seconds"] - 3.9) < 0.1
|
||||
assert metadata["length_seconds"] == pytest.approx(10.0, abs=0.1)
|
||||
assert metadata["length"] == str(
|
||||
datetime.timedelta(seconds=metadata["length_seconds"])
|
||||
)
|
||||
|
|
|
@ -4,9 +4,11 @@ from tempfile import TemporaryDirectory
|
|||
|
||||
import pytest
|
||||
|
||||
AUDIO_FILE = "tests/test_data/44100Hz-16bit-mono.mp3"
|
||||
AUDIO_FILENAME = os.path.basename(AUDIO_FILE)
|
||||
AUDIO_IMPORT_DEST = "Test Artist/Test Album/44100Hz-16bit-mono.mp3"
|
||||
from .fixtures import fixtures_path
|
||||
|
||||
AUDIO_FILENAME = "s1-stereo-tagged.mp3"
|
||||
AUDIO_FILE = fixtures_path / AUDIO_FILENAME
|
||||
AUDIO_IMPORT_DEST = f"Test Artist/Test Album/{AUDIO_FILENAME}"
|
||||
|
||||
# TODO: Use pathlib for file manipulation
|
||||
|
||||
|
|
|
@ -1,47 +1,38 @@
|
|||
import pytest
|
||||
from airtime_analyzer.cuepoint_analyzer import CuePointAnalyzer
|
||||
|
||||
from .fixtures import FILE_INVALID_DRM, FILES, Fixture
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"filepath",
|
||||
[
|
||||
("tests/test_data/44100Hz-16bit-mono.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-dualmono.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-stereo.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-stereo-utf8.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-simplestereo.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-jointstereo.mp3"),
|
||||
# ("tests/test_data/44100Hz-16bit-mp3-missingid3header.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-mono.ogg"),
|
||||
("tests/test_data/44100Hz-16bit-stereo.ogg"),
|
||||
# ("tests/test_data/44100Hz-16bit-stereo-invalid.wma"),
|
||||
("tests/test_data/44100Hz-16bit-stereo.m4a"),
|
||||
("tests/test_data/44100Hz-16bit-stereo.wav"),
|
||||
],
|
||||
"filepath,length,cuein,cueout",
|
||||
map(lambda i: (str(i.path), i.length, i.cuein, i.cueout), FILES),
|
||||
)
|
||||
def test_analyze(filepath):
|
||||
def test_analyze(filepath, length, cuein, cueout):
|
||||
metadata = CuePointAnalyzer.analyze(filepath, dict())
|
||||
|
||||
# We give silan some leeway here by specifying a tolerance
|
||||
tolerance_seconds = 0.1
|
||||
length_seconds = 3.9
|
||||
assert abs(metadata["length_seconds"] - length_seconds) < tolerance_seconds
|
||||
assert abs(float(metadata["cuein"])) < tolerance_seconds
|
||||
assert abs(float(metadata["cueout"]) - length_seconds) < tolerance_seconds
|
||||
assert metadata["length_seconds"] == pytest.approx(length, abs=0.1)
|
||||
|
||||
# Silan does not work with m4a files yet
|
||||
if filepath.endswith("m4a"):
|
||||
return
|
||||
|
||||
assert float(metadata["cuein"]) == pytest.approx(cuein, abs=0.5)
|
||||
assert float(metadata["cueout"]) == pytest.approx(cueout, abs=0.5)
|
||||
|
||||
|
||||
def test_analyze_missing_silan():
|
||||
old = CuePointAnalyzer.SILAN_EXECUTABLE
|
||||
CuePointAnalyzer.SILAN_EXECUTABLE = "foobar"
|
||||
CuePointAnalyzer.analyze("tests/test_data/44100Hz-16bit-mono.mp3", dict())
|
||||
CuePointAnalyzer.analyze(str(FILES[0].path), dict())
|
||||
CuePointAnalyzer.SILAN_EXECUTABLE = old
|
||||
|
||||
|
||||
def test_analyze_invalid_filepath():
|
||||
with pytest.raises(KeyError):
|
||||
test_analyze("non-existent-file")
|
||||
test_analyze("non-existent-file", None, None, None)
|
||||
|
||||
|
||||
def test_analyze_invalid_wma():
|
||||
with pytest.raises(KeyError):
|
||||
test_analyze("tests/test_data/44100Hz-16bit-stereo-invalid.wma")
|
||||
test_analyze(FILE_INVALID_DRM, None, None, None)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
s*-*
|
|
@ -0,0 +1,282 @@
|
|||
from collections import namedtuple
|
||||
from datetime import timedelta
|
||||
from pathlib import Path
|
||||
|
||||
from pytest import approx
|
||||
|
||||
here = Path(__file__).parent
|
||||
fixtures_path = here
|
||||
|
||||
FILE_INVALID_DRM = here / "invalid.wma"
|
||||
FILE_INVALID_TXT = here / "invalid.txt"
|
||||
|
||||
Fixture = namedtuple(
|
||||
"Fixture",
|
||||
["path", "length", "cuein", "cueout", "replaygain"],
|
||||
)
|
||||
|
||||
# length,cuein,cueout
|
||||
s1 = [10.0, 2.3, 10.0]
|
||||
s2 = [3.9, 0.0, 3.9]
|
||||
|
||||
FILES = [
|
||||
# Sample 1 MP3
|
||||
Fixture(here / "s1-jointstereo.mp3", *s1, -1.6),
|
||||
Fixture(here / "s1-mono.mp3", *s1, -0.7),
|
||||
Fixture(here / "s1-stereo.mp3", *s1, -1.6),
|
||||
# Sample 1 MP3 -12dB
|
||||
Fixture(here / "s1-mono-12.mp3", *s1, +8.3),
|
||||
Fixture(here / "s1-stereo-12.mp3", *s1, +10.0),
|
||||
# Sample 1 MP3 +12dB
|
||||
Fixture(here / "s1-mono+12.mp3", *s1, -13.6),
|
||||
Fixture(here / "s1-stereo+12.mp3", *s1, -12.0),
|
||||
# Sample 1 FLAC
|
||||
Fixture(here / "s1-mono.flac", *s1, -1.6),
|
||||
Fixture(here / "s1-stereo.flac", *s1, -2.3),
|
||||
# Sample 1 FLAC -12dB
|
||||
Fixture(here / "s1-mono-12.flac", *s1, +10.0),
|
||||
Fixture(here / "s1-stereo-12.flac", *s1, +9.3),
|
||||
# Sample 1 FLAC +12dB
|
||||
Fixture(here / "s1-mono+12.flac", *s1, -12.0),
|
||||
Fixture(here / "s1-stereo+12.flac", *s1, -12.0),
|
||||
# Sample 1 AAC
|
||||
Fixture(here / "s1-mono.m4a", *s1, -4.5),
|
||||
Fixture(here / "s1-stereo.m4a", *s1, -2.3),
|
||||
# Sample 1 Vorbis
|
||||
Fixture(here / "s1-mono.ogg", *s1, -4.3),
|
||||
Fixture(here / "s1-stereo.ogg", *s1, -2.3),
|
||||
# Sample 2 MP3
|
||||
Fixture(here / "s2-jointstereo.mp3", *s2, 6.1),
|
||||
Fixture(here / "s2-mono.mp3", *s2, 6.1),
|
||||
Fixture(here / "s2-stereo.mp3", *s2, 6.1),
|
||||
# Sample 2 FLAC
|
||||
Fixture(here / "s2-mono.flac", *s2, 5.2),
|
||||
Fixture(here / "s2-stereo.flac", *s2, 5.2),
|
||||
# Sample 2 AAC
|
||||
Fixture(here / "s2-mono.m4a", *s2, 2.6),
|
||||
Fixture(here / "s2-stereo.m4a", *s2, 6.1),
|
||||
# Sample 2 Vorbis
|
||||
Fixture(here / "s2-mono.ogg", *s2, 2.3),
|
||||
Fixture(here / "s2-stereo.ogg", *s2, 5.2),
|
||||
]
|
||||
|
||||
FixtureMeta = namedtuple(
|
||||
"FixtureMeta",
|
||||
["path", "metadata"],
|
||||
)
|
||||
|
||||
meta = {
|
||||
"cuein": 0.0,
|
||||
"sample_rate": 48000,
|
||||
"length": str(timedelta(seconds=10)),
|
||||
"length_seconds": approx(10.0, abs=0.1),
|
||||
"ftype": "audioclip",
|
||||
"hidden": False,
|
||||
# Tags
|
||||
"album_title": "Test Album",
|
||||
"artist_name": "Test Artist",
|
||||
"track_title": "Test Title",
|
||||
"track_number": "1",
|
||||
"track_total": "10",
|
||||
"year": "1999",
|
||||
"genre": "Test Genre",
|
||||
"comment": "Test Comment",
|
||||
}
|
||||
|
||||
FILES_TAGGED = [
|
||||
FixtureMeta(
|
||||
here / "s1-jointstereo-tagged.mp3",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(128000, abs=1e2),
|
||||
"channels": 2,
|
||||
"filesize": approx(161094, abs=1e2),
|
||||
"mime": "audio/mp3",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-mono-tagged.mp3",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(64000, abs=1e2),
|
||||
"channels": 1,
|
||||
"filesize": approx(80646, abs=1e2),
|
||||
"mime": "audio/mp3",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-stereo-tagged.mp3",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(128000, abs=1e2),
|
||||
"channels": 2,
|
||||
"filesize": approx(161094, abs=1e2),
|
||||
"mime": "audio/mp3",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-mono-tagged.flac",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(454468, abs=1e2),
|
||||
"channels": 1,
|
||||
"filesize": approx(576516, abs=1e2),
|
||||
"mime": "audio/flac",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-stereo-tagged.flac",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(687113, abs=1e2),
|
||||
"channels": 2,
|
||||
"filesize": approx(867323, abs=1e2),
|
||||
"mime": "audio/flac",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-mono-tagged.m4a",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(65000, abs=5e4),
|
||||
"channels": 2, # Weird
|
||||
"filesize": approx(80000, abs=1e5),
|
||||
"mime": "audio/mp4",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-stereo-tagged.m4a",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(128000, abs=1e5),
|
||||
"channels": 2,
|
||||
"filesize": approx(150000, abs=1e5),
|
||||
"mime": "audio/mp4",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-mono-tagged.ogg",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(80000, abs=1e2),
|
||||
"channels": 1,
|
||||
"filesize": approx(81340, abs=1e2),
|
||||
"mime": "audio/vorbis",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-stereo-tagged.ogg",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(112000, abs=1e2),
|
||||
"channels": 2,
|
||||
"filesize": approx(104036, abs=1e2),
|
||||
"mime": "audio/vorbis",
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
meta = {
|
||||
**meta,
|
||||
"album_title": "Ä ä Ü ü ß",
|
||||
"artist_name": "てすと",
|
||||
"track_title": "アイウエオカキクケコサシスセソタチツテ",
|
||||
"track_number": "1",
|
||||
"track_total": "10",
|
||||
"year": "1999",
|
||||
"genre": "Я Б Г Д Ж Й",
|
||||
"comment": "Ł Ą Ż Ę Ć Ń Ś Ź",
|
||||
}
|
||||
|
||||
FILES_TAGGED += [
|
||||
FixtureMeta(
|
||||
here / "s1-jointstereo-tagged-utf8.mp3",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(128000, abs=1e2),
|
||||
"channels": 2,
|
||||
"filesize": approx(161161, abs=1e2),
|
||||
"mime": "audio/mp3",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-mono-tagged-utf8.mp3",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(64000, abs=1e2),
|
||||
"channels": 1,
|
||||
"filesize": approx(80713, abs=1e2),
|
||||
"mime": "audio/mp3",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-stereo-tagged-utf8.mp3",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(128000, abs=1e2),
|
||||
"channels": 2,
|
||||
"filesize": approx(161161, abs=1e2),
|
||||
"mime": "audio/mp3",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-mono-tagged-utf8.flac",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(454468, abs=1e2),
|
||||
"channels": 1,
|
||||
"filesize": approx(576583, abs=1e2),
|
||||
"mime": "audio/flac",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-stereo-tagged-utf8.flac",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(687113, abs=1e2),
|
||||
"channels": 2,
|
||||
"filesize": approx(867390, abs=1e2),
|
||||
"mime": "audio/flac",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-mono-tagged-utf8.m4a",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(65000, abs=5e4),
|
||||
"channels": 2, # Weird
|
||||
"filesize": approx(80000, abs=1e5),
|
||||
"mime": "audio/mp4",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-stereo-tagged-utf8.m4a",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(128000, abs=1e5),
|
||||
"channels": 2,
|
||||
"filesize": approx(150000, abs=1e5),
|
||||
"mime": "audio/mp4",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-mono-tagged-utf8.ogg",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(80000, abs=1e2),
|
||||
"channels": 1,
|
||||
"filesize": approx(81408, abs=1e2),
|
||||
"mime": "audio/vorbis",
|
||||
},
|
||||
),
|
||||
FixtureMeta(
|
||||
here / "s1-stereo-tagged-utf8.ogg",
|
||||
{
|
||||
**meta,
|
||||
"bit_rate": approx(112000, abs=1e2),
|
||||
"channels": 2,
|
||||
"filesize": approx(104104, abs=1e2),
|
||||
"mime": "audio/vorbis",
|
||||
},
|
||||
),
|
||||
]
|
|
@ -0,0 +1,92 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -u
|
||||
|
||||
error() {
|
||||
echo >&2 "error: $*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
command -v ffmpeg > /dev/null || error "ffmpeg command not found!"
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")" || error "could not change directory!"
|
||||
|
||||
# <metadata> <input> <output>
|
||||
tag() {
|
||||
metadata="$1" && shift
|
||||
input="$1" && shift
|
||||
output="$1" && shift
|
||||
if [[ ! -f "$output" ]]; then
|
||||
echo "tagging $output from $input with $metadata"
|
||||
ffmpeg -y -i "$input" -f ffmetadata -i "$metadata" -c copy -map_metadata 1 "$output" \
|
||||
2> /dev/null ||
|
||||
error "could not tag $output"
|
||||
fi
|
||||
}
|
||||
|
||||
# <input> <output> <flags...>
|
||||
generate() {
|
||||
input="$1" && shift
|
||||
output="$1" && shift
|
||||
if [[ ! -f "$output" ]]; then
|
||||
echo "generating $output from $input"
|
||||
ffmpeg -y -i "$input" -vn "$@" "$output" \
|
||||
2> /dev/null ||
|
||||
error "could not generate $output"
|
||||
fi
|
||||
}
|
||||
|
||||
# Generate sample 1
|
||||
generate s1.flac s1-mono.flac -ac 1 -acodec flac
|
||||
generate s1.flac s1-mono.m4a -ac 1 -acodec aac
|
||||
generate s1.flac s1-mono.mp3 -ac 1 -acodec libmp3lame
|
||||
generate s1.flac s1-mono.ogg -ac 1 -acodec libvorbis
|
||||
generate s1.flac s1-stereo.flac -ac 2 -acodec flac
|
||||
generate s1.flac s1-stereo.m4a -ac 2 -acodec aac
|
||||
generate s1.flac s1-stereo.mp3 -ac 2 -acodec libmp3lame
|
||||
generate s1.flac s1-stereo.ogg -ac 2 -acodec libvorbis
|
||||
generate s1.flac s1-jointstereo.mp3 -ac 2 -acodec libmp3lame -joint_stereo 1
|
||||
|
||||
# Generate sample 1 +/-12dB
|
||||
generate s1.flac s1-mono-12.flac -ac 1 -acodec flac -af volume=-12dB
|
||||
generate s1.flac s1-stereo-12.flac -ac 2 -acodec flac -af volume=-12dB
|
||||
generate s1.flac s1-mono-12.mp3 -ac 1 -acodec libmp3lame -af volume=-12dB
|
||||
generate s1.flac s1-stereo-12.mp3 -ac 2 -acodec libmp3lame -af volume=-12dB
|
||||
|
||||
generate s1.flac s1-mono+12.flac -ac 1 -acodec flac -af volume=+12dB
|
||||
generate s1.flac s1-stereo+12.flac -ac 2 -acodec flac -af volume=+12dB
|
||||
generate s1.flac s1-mono+12.mp3 -ac 1 -acodec libmp3lame -af volume=+12dB
|
||||
generate s1.flac s1-stereo+12.mp3 -ac 2 -acodec libmp3lame -af volume=+12dB
|
||||
|
||||
# Generate sample 2
|
||||
generate s2.flac s2-mono.flac -ac 1 -acodec flac
|
||||
generate s2.flac s2-mono.m4a -ac 1 -acodec aac
|
||||
generate s2.flac s2-mono.mp3 -ac 1 -acodec libmp3lame
|
||||
generate s2.flac s2-mono.ogg -ac 1 -acodec libvorbis
|
||||
generate s2.flac s2-stereo.flac -ac 2 -acodec flac
|
||||
generate s2.flac s2-stereo.m4a -ac 2 -acodec aac
|
||||
generate s2.flac s2-stereo.mp3 -ac 2 -acodec libmp3lame
|
||||
generate s2.flac s2-stereo.ogg -ac 2 -acodec libvorbis
|
||||
generate s2.flac s2-jointstereo.mp3 -ac 2 -acodec libmp3lame -joint_stereo 1
|
||||
|
||||
# Tag sample 1
|
||||
tag metadata.txt s1-mono.flac s1-mono-tagged.flac
|
||||
tag metadata.txt s1-mono.m4a s1-mono-tagged.m4a
|
||||
tag metadata.txt s1-mono.mp3 s1-mono-tagged.mp3
|
||||
tag metadata.txt s1-mono.ogg s1-mono-tagged.ogg
|
||||
tag metadata.txt s1-stereo.flac s1-stereo-tagged.flac
|
||||
tag metadata.txt s1-stereo.m4a s1-stereo-tagged.m4a
|
||||
tag metadata.txt s1-stereo.mp3 s1-stereo-tagged.mp3
|
||||
tag metadata.txt s1-stereo.ogg s1-stereo-tagged.ogg
|
||||
tag metadata.txt s1-jointstereo.mp3 s1-jointstereo-tagged.mp3
|
||||
|
||||
# Tag utf8 sample 1
|
||||
tag metadata-utf8.txt s1-mono.flac s1-mono-tagged-utf8.flac
|
||||
tag metadata-utf8.txt s1-mono.m4a s1-mono-tagged-utf8.m4a
|
||||
tag metadata-utf8.txt s1-mono.mp3 s1-mono-tagged-utf8.mp3
|
||||
tag metadata-utf8.txt s1-mono.ogg s1-mono-tagged-utf8.ogg
|
||||
tag metadata-utf8.txt s1-stereo.flac s1-stereo-tagged-utf8.flac
|
||||
tag metadata-utf8.txt s1-stereo.m4a s1-stereo-tagged-utf8.m4a
|
||||
tag metadata-utf8.txt s1-stereo.mp3 s1-stereo-tagged-utf8.mp3
|
||||
tag metadata-utf8.txt s1-stereo.ogg s1-stereo-tagged-utf8.ogg
|
||||
tag metadata-utf8.txt s1-jointstereo.mp3 s1-jointstereo-tagged-utf8.mp3
|
|
@ -0,0 +1,8 @@
|
|||
;FFMETADATA1
|
||||
album=Ä ä Ü ü ß
|
||||
artist=てすと
|
||||
title=アイウエオカキクケコサシスセソタチツテ
|
||||
track=1/10
|
||||
date=1999
|
||||
genre=Я Б Г Д Ж Й
|
||||
comment=Ł Ą Ż Ę Ć Ń Ś Ź
|
|
@ -0,0 +1,8 @@
|
|||
;FFMETADATA1
|
||||
album=Test Album
|
||||
artist=Test Artist
|
||||
title=Test Title
|
||||
track=1/10
|
||||
date=1999
|
||||
genre=Test Genre
|
||||
comment=Test Comment
|
Binary file not shown.
Binary file not shown.
|
@ -1,10 +1,12 @@
|
|||
import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
import mock
|
||||
import mutagen
|
||||
import pytest
|
||||
from airtime_analyzer.metadata_analyzer import MetadataAnalyzer
|
||||
|
||||
from .fixtures import FILE_INVALID_DRM, FILE_INVALID_TXT, FILES_TAGGED, FixtureMeta
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params,exception",
|
||||
|
@ -18,227 +20,41 @@ def test_analyze_wrong_params(params, exception):
|
|||
MetadataAnalyzer.analyze(*params)
|
||||
|
||||
|
||||
def default_metadata(metadata):
|
||||
return {
|
||||
"album_title": "Test Album",
|
||||
"artist_name": "Test Artist",
|
||||
"cuein": 0.0,
|
||||
"cueout": "0:00:03.839410",
|
||||
"ftype": "audioclip",
|
||||
"genre": "Test Genre",
|
||||
"hidden": False,
|
||||
"length_seconds": metadata["length_seconds"],
|
||||
"length": str(datetime.timedelta(seconds=metadata["length_seconds"])),
|
||||
"sample_rate": 44100,
|
||||
"track_number": "1",
|
||||
"track_title": "Test Title",
|
||||
"year": "1999",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"filepath,expected",
|
||||
[
|
||||
(
|
||||
"tests/test_data/44100Hz-16bit-mono.mp3",
|
||||
{
|
||||
"bit_rate": 63998,
|
||||
"channels": 1,
|
||||
"filesize": 32298,
|
||||
"md5": "a93c9503c85cd2fbe7658711a08c24b1",
|
||||
"mime": "audio/mp3",
|
||||
"track_total": "10",
|
||||
},
|
||||
),
|
||||
(
|
||||
"tests/test_data/44100Hz-16bit-dualmono.mp3",
|
||||
{
|
||||
"bit_rate": 127998,
|
||||
"channels": 2,
|
||||
"filesize": 63436,
|
||||
"md5": "aee8bf340b484f921bca99390962f0d5",
|
||||
"mime": "audio/mp3",
|
||||
"track_total": "10",
|
||||
},
|
||||
),
|
||||
(
|
||||
"tests/test_data/44100Hz-16bit-stereo.mp3",
|
||||
{
|
||||
"bit_rate": 127998,
|
||||
"channels": 2,
|
||||
"filesize": 63436,
|
||||
"md5": "063b20072f71a18b9d4f14434286fdc5",
|
||||
"mime": "audio/mp3",
|
||||
"track_total": "10",
|
||||
},
|
||||
),
|
||||
(
|
||||
"tests/test_data/44100Hz-16bit-stereo-utf8.mp3",
|
||||
{
|
||||
"album_title": "Ä ä Ü ü ß",
|
||||
"artist_name": "てすと",
|
||||
"bit_rate": 127998,
|
||||
"channels": 2,
|
||||
"filesize": 63436,
|
||||
"genre": "Я Б Г Д Ж Й",
|
||||
"md5": "0bb41e7f65db3f31cf449de18f713fca",
|
||||
"mime": "audio/mp3",
|
||||
"track_title": "アイウエオカキクケコサシスセソタチツテ",
|
||||
"track_total": "10",
|
||||
},
|
||||
),
|
||||
(
|
||||
"tests/test_data/44100Hz-16bit-simplestereo.mp3",
|
||||
{
|
||||
"bit_rate": 127998,
|
||||
"channels": 2,
|
||||
"filesize": 63436,
|
||||
"md5": "2330d4429bec7b35fa40185319069267",
|
||||
"mime": "audio/mp3",
|
||||
"track_total": "10",
|
||||
},
|
||||
),
|
||||
(
|
||||
"tests/test_data/44100Hz-16bit-jointstereo.mp3",
|
||||
{
|
||||
"bit_rate": 127998,
|
||||
"channels": 2,
|
||||
"filesize": 63436,
|
||||
"md5": "063b20072f71a18b9d4f14434286fdc5",
|
||||
"mime": "audio/mp3",
|
||||
"track_total": "10",
|
||||
},
|
||||
),
|
||||
# (
|
||||
# "tests/test_data/44100Hz-16bit-mp3-missingid3header.mp3",
|
||||
# {
|
||||
# "bit_rate": 63998,
|
||||
# "channels": 1,
|
||||
# "filesize": 32298,
|
||||
# "md5": "a93c9503c85cd2fbe7658711a08c24b1",
|
||||
# "mime": "audio/mp3",
|
||||
# "track_total": "10",
|
||||
# },
|
||||
# ),
|
||||
(
|
||||
"tests/test_data/44100Hz-16bit-mono.ogg",
|
||||
{
|
||||
"bit_rate": 80000,
|
||||
"channels": 1,
|
||||
"filesize": 36326,
|
||||
"md5": "699e091994f3b69a77ed074951520e18",
|
||||
"mime": "audio/vorbis",
|
||||
"track_total": "10",
|
||||
"comment": "Test Comment",
|
||||
},
|
||||
),
|
||||
(
|
||||
"tests/test_data/44100Hz-16bit-stereo.ogg",
|
||||
{
|
||||
"bit_rate": 112000,
|
||||
"channels": 2,
|
||||
"filesize": 41081,
|
||||
"md5": "185a3b9cd1bd2db4d168ff9c2c86046e",
|
||||
"mime": "audio/vorbis",
|
||||
"track_total": "10",
|
||||
"comment": "Test Comment",
|
||||
},
|
||||
),
|
||||
# (
|
||||
# "tests/test_data/44100Hz-16bit-stereo-invalid.wma",
|
||||
# {
|
||||
# "bit_rate": 63998,
|
||||
# "channels": 1,
|
||||
# "filesize": 32298,
|
||||
# "md5": "a93c9503c85cd2fbe7658711a08c24b1",
|
||||
# "mime": "audio/mp3",
|
||||
# "track_total": "10",
|
||||
# },
|
||||
# ),
|
||||
(
|
||||
"tests/test_data/44100Hz-16bit-stereo.m4a",
|
||||
{
|
||||
"bit_rate": 102619,
|
||||
"channels": 2,
|
||||
"cueout": "0:00:03.862630",
|
||||
"filesize": 51972,
|
||||
"md5": "c2c822e0cd6c03f3f6bd7158a6ed8c56",
|
||||
"mime": "audio/mp4",
|
||||
# "track_total": "10",
|
||||
"comment": "Test Comment",
|
||||
},
|
||||
),
|
||||
# (
|
||||
# "tests/test_data/44100Hz-16bit-stereo.wav",
|
||||
# {
|
||||
# "bit_rate": 112000,
|
||||
# "channels": 2,
|
||||
# "filesize": 677316,
|
||||
# "md5": "6bd5df4f161375e4634cbd4968fb5c23",
|
||||
# "mime": "audio/x-wav",
|
||||
# "track_total": "10",
|
||||
# "comment": "Test Comment",
|
||||
# },
|
||||
# ),
|
||||
],
|
||||
"filepath,metadata",
|
||||
map(lambda i: (str(i.path), i.metadata), FILES_TAGGED),
|
||||
)
|
||||
def test_analyze(filepath, expected):
|
||||
metadata = MetadataAnalyzer.analyze(filepath, dict())
|
||||
assert abs(metadata["length_seconds"] - 3.9) < 0.1
|
||||
assert metadata == {**default_metadata(metadata), **expected}
|
||||
def test_analyze(filepath: str, metadata: dict):
|
||||
found = MetadataAnalyzer.analyze(filepath, dict())
|
||||
|
||||
# Mutagen does not support wav files yet
|
||||
if filepath.endswith("wav"):
|
||||
return
|
||||
|
||||
assert len(found["md5"]) == 32
|
||||
del found["md5"]
|
||||
|
||||
# Handle track formatted length/cueout
|
||||
assert metadata["length"] in found["length"]
|
||||
assert metadata["length"] in found["cueout"]
|
||||
del metadata["length"]
|
||||
del found["length"]
|
||||
del found["cueout"]
|
||||
|
||||
# mp3,ogg,flac files does not support comments yet
|
||||
if not filepath.endswith("m4a"):
|
||||
del metadata["comment"]
|
||||
|
||||
assert found == metadata
|
||||
|
||||
|
||||
def test_invalid_wma():
|
||||
metadata = MetadataAnalyzer.analyze(
|
||||
"tests/test_data/44100Hz-16bit-stereo-invalid.wma", dict()
|
||||
)
|
||||
metadata = MetadataAnalyzer.analyze(str(FILE_INVALID_DRM), dict())
|
||||
assert metadata["mime"] == "audio/x-ms-wma"
|
||||
|
||||
|
||||
def test_wav_stereo():
|
||||
metadata = MetadataAnalyzer.analyze(
|
||||
"tests/test_data/44100Hz-16bit-stereo.wav", dict()
|
||||
)
|
||||
assert metadata == {
|
||||
"sample_rate": 44100,
|
||||
"channels": 2,
|
||||
"filesize": 677316,
|
||||
"md5": "6bd5df4f161375e4634cbd4968fb5c23",
|
||||
"mime": "audio/x-wav",
|
||||
"cueout": "0:00:03.839410",
|
||||
"ftype": "audioclip",
|
||||
"hidden": False,
|
||||
"length": "0:00:03.839410",
|
||||
"length_seconds": 3.8394104308390022,
|
||||
}
|
||||
|
||||
|
||||
def test_mp3_bad_channels():
|
||||
"""
|
||||
Test an mp3 file where the number of channels is invalid or missing.
|
||||
"""
|
||||
# It'd be a pain in the ass to construct a real MP3 with an invalid number
|
||||
# of channels by hand because that value is stored in every MP3 frame in the file
|
||||
filename = "tests/test_data/44100Hz-16bit-mono.mp3"
|
||||
audio_file = mutagen.File(filename, easy=True)
|
||||
audio_file.info.mode = 1777
|
||||
with mock.patch("airtime_analyzer.metadata_analyzer.mutagen") as mock_mutagen:
|
||||
mock_mutagen.File.return_value = audio_file
|
||||
|
||||
metadata = MetadataAnalyzer.analyze(filename, dict())
|
||||
assert metadata == {
|
||||
**default_metadata(metadata),
|
||||
"bit_rate": 63998,
|
||||
"channels": 1,
|
||||
"filesize": 32298,
|
||||
"md5": "a93c9503c85cd2fbe7658711a08c24b1",
|
||||
"mime": "audio/mp3",
|
||||
"track_total": "10",
|
||||
}
|
||||
|
||||
|
||||
def test_unparsable_file():
|
||||
metadata = MetadataAnalyzer.analyze("tests/test_data/unparsable.txt", dict())
|
||||
metadata = MetadataAnalyzer.analyze(str(FILE_INVALID_TXT), dict())
|
||||
assert metadata == {
|
||||
"filesize": 10,
|
||||
"ftype": "audioclip",
|
||||
|
|
|
@ -4,23 +4,12 @@ from airtime_analyzer.playability_analyzer import (
|
|||
UnplayableFileError,
|
||||
)
|
||||
|
||||
from .fixtures import FILE_INVALID_DRM, FILES, Fixture
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"filepath",
|
||||
[
|
||||
("tests/test_data/44100Hz-16bit-mono.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-dualmono.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-stereo.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-stereo-utf8.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-simplestereo.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-jointstereo.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-mp3-missingid3header.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-mono.ogg"),
|
||||
("tests/test_data/44100Hz-16bit-stereo.ogg"),
|
||||
# ("tests/test_data/44100Hz-16bit-stereo-invalid.wma"),
|
||||
("tests/test_data/44100Hz-16bit-stereo.m4a"),
|
||||
("tests/test_data/44100Hz-16bit-stereo.wav"),
|
||||
],
|
||||
map(lambda i: str(i.path), FILES),
|
||||
)
|
||||
def test_analyze(filepath):
|
||||
PlayabilityAnalyzer.analyze(filepath, dict())
|
||||
|
@ -29,7 +18,7 @@ def test_analyze(filepath):
|
|||
def test_analyze_missing_liquidsoap():
|
||||
old = PlayabilityAnalyzer.LIQUIDSOAP_EXECUTABLE
|
||||
PlayabilityAnalyzer.LIQUIDSOAP_EXECUTABLE = "foobar"
|
||||
PlayabilityAnalyzer.analyze("tests/test_data/44100Hz-16bit-mono.mp3", dict())
|
||||
PlayabilityAnalyzer.analyze(str(FILES[0].path), dict())
|
||||
PlayabilityAnalyzer.LIQUIDSOAP_EXECUTABLE = old
|
||||
|
||||
|
||||
|
@ -41,7 +30,7 @@ def test_analyze_invalid_filepath():
|
|||
# This test is not be consistent with all Liquidsoap versions.
|
||||
def test_analyze_invalid_wma():
|
||||
with pytest.raises(UnplayableFileError):
|
||||
test_analyze("tests/test_data/44100Hz-16bit-stereo-invalid.wma")
|
||||
test_analyze(FILE_INVALID_DRM)
|
||||
|
||||
|
||||
def test_analyze_unknown():
|
||||
|
|
|
@ -1,45 +1,30 @@
|
|||
import pytest
|
||||
from airtime_analyzer.replaygain_analyzer import ReplayGainAnalyzer
|
||||
|
||||
from .fixtures import FILE_INVALID_DRM, FILES, Fixture
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"filepath",
|
||||
[
|
||||
("tests/test_data/44100Hz-16bit-mono.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-dualmono.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-stereo.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-stereo-utf8.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-simplestereo.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-jointstereo.mp3"),
|
||||
# ("tests/test_data/44100Hz-16bit-mp3-missingid3header.mp3"),
|
||||
("tests/test_data/44100Hz-16bit-mono.ogg"),
|
||||
("tests/test_data/44100Hz-16bit-stereo.ogg"),
|
||||
# ("tests/test_data/44100Hz-16bit-stereo-invalid.wma"),
|
||||
("tests/test_data/44100Hz-16bit-stereo.m4a"),
|
||||
# ("tests/test_data/44100Hz-16bit-stereo.wav"), # WAV is not supported by rgain3
|
||||
],
|
||||
"filepath,replaygain",
|
||||
map(lambda i: (str(i.path), i.replaygain), FILES),
|
||||
)
|
||||
def test_analyze(filepath):
|
||||
def test_analyze(filepath, replaygain):
|
||||
metadata = ReplayGainAnalyzer.analyze(filepath, dict())
|
||||
|
||||
# We give rgain3 some leeway here by specifying a tolerance
|
||||
tolerance = 0.60
|
||||
expected_replaygain = 5.2
|
||||
assert abs(metadata["replay_gain"] - expected_replaygain) < tolerance
|
||||
assert metadata["replay_gain"] == pytest.approx(replaygain, abs=0.6)
|
||||
|
||||
|
||||
def test_analyze_missing_replaygain():
|
||||
old = ReplayGainAnalyzer.REPLAYGAIN_EXECUTABLE
|
||||
ReplayGainAnalyzer.REPLAYGAIN_EXECUTABLE = "foobar"
|
||||
ReplayGainAnalyzer.analyze("tests/test_data/44100Hz-16bit-mono.mp3", dict())
|
||||
ReplayGainAnalyzer.analyze(str(FILES[0].path), dict())
|
||||
ReplayGainAnalyzer.REPLAYGAIN_EXECUTABLE = old
|
||||
|
||||
|
||||
def test_analyze_invalid_filepath():
|
||||
with pytest.raises(KeyError):
|
||||
test_analyze("non-existent-file")
|
||||
test_analyze("non-existent-file", None)
|
||||
|
||||
|
||||
def test_analyze_invalid_wma():
|
||||
with pytest.raises(KeyError):
|
||||
test_analyze("tests/test_data/44100Hz-16bit-stereo-invalid.wma")
|
||||
test_analyze(FILE_INVALID_DRM, None)
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue