1# Copyright 2013 Christoph Reiter
2#
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 2 of the License, or
6# (at your option) any later version.
7
8import os
9from io import BytesIO
10import mutagen
11
12from tests import TestCase, get_data_path
13from quodlibet.formats.mp4 import MP4File
14from quodlibet.formats._image import EmbeddedImage
15
16import mutagen.mp4
17
18from .helper import get_temp_copy
19
20
21class TMP4File(TestCase):
22
23    def setUp(self):
24        self.f = get_temp_copy(get_data_path('test.m4a'))
25        self.song = MP4File(self.f)
26
27    def tearDown(self):
28        os.unlink(self.f)
29
30    def _assert_tag_supported(self, tag, value="SomeTestValue"):
31        self.song[tag] = value
32        self.song.write()
33        self.song.reload()
34        self.assertEqual(self.song(tag), value)
35
36    def test_format(self):
37        self.assertEqual(self.song("~format"), "MPEG-4")
38
39    def test_codec(self):
40        self.assertEqual(self.song("~codec"), "AAC LC")
41
42    def test_encoding(self):
43        self.assertEqual(self.song("~encoding"), "FAAC 1.24")
44
45    def test_mb_release_track_id(self):
46        tag = mutagen.mp4.MP4(self.f)
47        tag["----:com.apple.iTunes:MusicBrainz Release Track Id"] = [b"foo"]
48        tag.save()
49        song = MP4File(self.f)
50        self.assertEqual(song("musicbrainz_releasetrackid"), u"foo")
51        song["musicbrainz_releasetrackid"] = u"bla"
52        song.write()
53        tag = mutagen.mp4.MP4(self.f)
54        self.assertEqual(
55            tag["----:com.apple.iTunes:MusicBrainz Release Track Id"],
56            [b"bla"])
57
58    def test_basic(self):
59        self._assert_tag_supported("title")
60        self._assert_tag_supported("artist")
61        self._assert_tag_supported("albumartist")
62        self._assert_tag_supported("album")
63        self._assert_tag_supported("genre")
64        self._assert_tag_supported("date")
65
66    def test_basic_numeric(self):
67        self._assert_tag_supported("tracknumber", "12")
68        self._assert_tag_supported("discnumber", "1")
69        self._assert_tag_supported("bpm", "132")
70
71    def test_less_common_tags(self):
72        self._assert_tag_supported("discsubtitle")
73        self._assert_tag_supported("mood")
74        self._assert_tag_supported("conductor")
75
76    def test_replaygain_tags(self):
77        self._assert_tag_supported('replaygain_album_gain', '-5.67 dB')
78        self._assert_tag_supported('replaygain_album_peak', '1.0')
79        self._assert_tag_supported('replaygain_track_gain', '-5.67 dB')
80        self._assert_tag_supported('replaygain_track_peak', '1.0')
81        self._assert_tag_supported('replaygain_reference_loudness', '89 dB')
82
83    def test_length(self):
84        self.assertAlmostEqual(self.song("~#length"), 3.7079, 3)
85
86    def test_bitrate(self):
87        self.assertEqual(self.song("~#bitrate"), 2)
88
89    def test_channels(self):
90        assert self.song("~#channels") == 2
91
92    def test_samplerate(self):
93        assert self.song("~#samplerate") == 44100
94
95    def test_bitdepth(self):
96        assert self.song("~#bitdepth") == 16
97
98    def test_bpm_rounds(self):
99        self.song["bpm"] = "98.76"
100        self.song.write()
101        self.song.reload()
102        self.assertEqual(self.song("bpm"), "99")
103        self.assertEqual(self.song("~#bpm"), 99)
104
105    def test_empty_disk_trkn(self):
106        for key in ["trkn", "disk"]:
107            tag = mutagen.mp4.MP4(self.f)
108            tag[key] = []
109            tag.save()
110            tag = mutagen.mp4.MP4(self.f)
111            assert tag[key] == []
112            self.song.reload()
113
114    def test_write(self):
115        self.song.write()
116
117    def test_can_change(self):
118        self.assertTrue(self.song.can_change("title"))
119        self.assertFalse(self.song.can_change("foobar"))
120        self.assertTrue("albumartist" in self.song.can_change())
121
122    def test_invalid(self):
123        path = get_data_path('empty.xm')
124        self.assertTrue(os.path.exists(path))
125        self.assertRaises(Exception, MP4File, path)
126
127    def test_get_image(self):
128        image = self.song.get_primary_image()
129        self.assertTrue(image)
130        self.assertEqual(image.mime_type, "image/png")
131
132    def test_get_images(self):
133        images = self.song.get_images()
134        self.assertTrue(images and len(images) == 2)
135
136    def test_get_image_non(self):
137        tag = mutagen.mp4.MP4(self.f)
138        tag.pop("covr", None)
139        tag.save()
140        self.song.reload()
141
142        self.assertFalse(self.song.get_primary_image())
143
144    def test_clear_images(self):
145        self.assertTrue(self.song.valid())
146        self.assertTrue(self.song.has_images)
147        self.song.clear_images()
148        self.assertFalse(self.song.has_images)
149        self.assertFalse(self.song.get_primary_image())
150
151        tag = mutagen.mp4.MP4(self.f)
152        self.assertFalse("covr" in tag)
153
154    def test_set_image(self):
155        self.assertTrue(self.song.has_images)
156        fileobj = BytesIO(b"foo")
157        image = EmbeddedImage(fileobj, "image/jpeg", 10, 10, 8)
158        self.song.set_image(image)
159        image = self.song.get_primary_image()
160        self.assertTrue(image)
161        self.assertEqual(image.read(), b"foo")
162        self.assertTrue(self.song.has_images)
163
164    def test_can_change_images(self):
165        self.assertTrue(self.song.can_change_images)
166
167    def test_can_multiple_values(self):
168        self.assertEqual(self.song.can_multiple_values(), [])
169        self.assertFalse(self.song.can_multiple_values("artist"))
170