def test_scan_has_chirp_tags(self):
        path = os.path.join(TESTDATA, "has_chirp_tags.mp3")
        fast_au_file = audio_file.scan_fast(path)
        slow_au_file = audio_file.scan(path)

        self.assertEqual(path, fast_au_file.path)
        self.assertEqual(path, slow_au_file.path)

        # This volume and timestamp is extracted from the UFID.
        self.assertEqual(123, fast_au_file.volume)
        self.assertEqual(1230519180, fast_au_file.import_timestamp)

        self.assertEqual(3918, fast_au_file.duration_ms)
        self.assertEqual(slow_au_file.duration_ms, fast_au_file.duration_ms)

        self.assertEqual(slow_au_file.fingerprint, fast_au_file.fingerprint)

        # Test file contains 150 frames for a total of 137,173 bytes.
        self.assertEqual(150, slow_au_file.frame_count)
        self.assertEqual(137173, slow_au_file.frame_size)
        self.assertEqual(path, slow_au_file.path)

        # The fast scan picks up an album ID stored in the tags,
        # the slow scan doesn't.  The test file is marked as having
        # an album ID of 123454321.
        self.assertEqual(123454321, fast_au_file.album_id)
        self.assertEqual(None, slow_au_file.album_id)
Exemple #2
0
    def test_scan_has_chirp_tags(self):
        path = os.path.join(TESTDATA, "has_chirp_tags.mp3")
        fast_au_file = audio_file.scan_fast(path)
        slow_au_file = audio_file.scan(path)

        self.assertEqual(path, fast_au_file.path)
        self.assertEqual(path, slow_au_file.path)

        # This volume and timestamp is extracted from the UFID.
        self.assertEqual(123, fast_au_file.volume)
        self.assertEqual(1230519180, fast_au_file.import_timestamp)

        self.assertEqual(3918, fast_au_file.duration_ms)
        self.assertEqual(slow_au_file.duration_ms, fast_au_file.duration_ms)

        self.assertEqual(slow_au_file.fingerprint, fast_au_file.fingerprint)

        # Test file contains 150 frames for a total of 137,173 bytes.
        self.assertEqual(150, slow_au_file.frame_count)
        self.assertEqual(137173, slow_au_file.frame_size)
        self.assertEqual(path, slow_au_file.path)

        # The fast scan picks up an album ID stored in the tags,
        # the slow scan doesn't.  The test file is marked as having
        # an album ID of 123454321.
        self.assertEqual(123454321, fast_au_file.album_id)
        self.assertEqual(None, slow_au_file.album_id)
Exemple #3
0
    def scan_fast(self):
        """Quickly scan all MP3 files in the dropbox.

        Returns:
          A dict mapping relative file paths to either audio_file.AudioFile
          objects, or to None in the case of a corrupted or unreadable file.
        """
        # Note the use of ad-hoc relativization in the path.
        return dict(
            (mp3_path[len(self._path):], audio_file.scan_fast(mp3_path))
            for mp3_path in self._all_files)
Exemple #4
0
    def scan_fast(self):
        """Quickly scan all MP3 files in the dropbox.

        Returns:
          A dict mapping relative file paths to either audio_file.AudioFile
          objects, or to None in the case of a corrupted or unreadable file.
        """
        # Note the use of ad-hoc relativization in the path.
        return dict(
            (mp3_path[len(self._path):], audio_file.scan_fast(mp3_path))
            for mp3_path in self._all_files)
Exemple #5
0
    def test_scan_no_chirp_tags(self):
        path = os.path.join(TESTDATA, "no_chirp_tags.mp3")
        fast_au_file = audio_file.scan_fast(path)
        self.assertEqual(None, fast_au_file.volume)
        self.assertEqual(None, fast_au_file.import_timestamp)
        self.assertEqual(None, fast_au_file.fingerprint)
        self.assertEqual(None, fast_au_file.frame_count)
        self.assertEqual(None, fast_au_file.frame_size)
        # File doesn't have a TLEN tag.
        self.assertEqual(None, fast_au_file.duration_ms)
        self.assertEqual(path, fast_au_file.path)

        slow_au_file = audio_file.scan(path)
        # The file's fingerprint is stashed in the UFID:test tag.
        fp = slow_au_file.mutagen_id3.get("UFID:test").data
        self.assertEqual(None, slow_au_file.volume)
        self.assertEqual(None, slow_au_file.import_timestamp)
        self.assertEqual(fp, slow_au_file.fingerprint)
        # Test file contains 150 frames for a total of 137,173 bytes.
        self.assertEqual(150, slow_au_file.frame_count)
        self.assertEqual(137173, slow_au_file.frame_size)
        self.assertEqual(path, slow_au_file.path)
Exemple #6
0
    def test_scan_fast_tag_handling(self):
        test_mp3 = mutagen.mp3.MP3()

        class MockInfo(object):
            pass

        test_mp3.info = MockInfo()
        test_mp3.add_tags()
        test_mp3.tags.add(ufid.ufid_tag(TEST_VOL, TEST_TS, TEST_FP))
        test_mp3.tags.add(mutagen.id3.TLEN(text=u"11111"))
        test_mp3.tags.add(
            mutagen.id3.TXXX(desc=constants.TXXX_ALBUM_ID_DESCRIPTION,
                             text=[u"222"]))
        test_mp3.tags.add(
            mutagen.id3.TXXX(desc=constants.TXXX_FRAME_COUNT_DESCRIPTION,
                             text=[u"333"]))
        test_mp3.tags.add(
            mutagen.id3.TXXX(desc=constants.TXXX_FRAME_SIZE_DESCRIPTION,
                             text=["444"]))
        for tag in test_mp3.tags.values():
            id3_text.standardize(tag)
        test_mp3.info.sample_rate = 5555
        test_mp3.info.bitrate = 6666
        test_mp3.info.mode = 2

        au_file = audio_file.scan_fast("/test/path",
                                       _read_id3_hook=lambda p: test_mp3)
        self.assertTrue(audio_file is not None)
        self.assertEqual("/test/path", au_file.path)
        self.assertEqual(TEST_VOL, au_file.volume)
        self.assertEqual(TEST_TS, au_file.import_timestamp)
        self.assertEqual(TEST_FP, au_file.fingerprint)
        self.assertEqual(11111, au_file.duration_ms)
        self.assertEqual(222, au_file.album_id)
        self.assertEqual(333, au_file.frame_count)
        self.assertEqual(444, au_file.frame_size)
        self.assertEqual(5555, au_file.mp3_header.sampling_rate_hz)
        self.assertEqual(6.666, au_file.mp3_header.bit_rate_kbps)
        self.assertEqual(2, au_file.mp3_header.channels)
    def test_scan_no_chirp_tags(self):
        path = os.path.join(TESTDATA, "no_chirp_tags.mp3")
        fast_au_file = audio_file.scan_fast(path)
        self.assertEqual(None, fast_au_file.volume)
        self.assertEqual(None, fast_au_file.import_timestamp)
        self.assertEqual(None, fast_au_file.fingerprint)
        self.assertEqual(None, fast_au_file.frame_count)
        self.assertEqual(None, fast_au_file.frame_size)
        # File doesn't have a TLEN tag.
        self.assertEqual(None, fast_au_file.duration_ms)
        self.assertEqual(path, fast_au_file.path)

        slow_au_file = audio_file.scan(path)
        # The file's fingerprint is stashed in the UFID:test tag.
        fp = slow_au_file.mutagen_id3.get("UFID:test").data
        self.assertEqual(None, slow_au_file.volume)
        self.assertEqual(None, slow_au_file.import_timestamp)
        self.assertEqual(fp, slow_au_file.fingerprint)
        # Test file contains 150 frames for a total of 137,173 bytes.
        self.assertEqual(150, slow_au_file.frame_count)
        self.assertEqual(137173, slow_au_file.frame_size)
        self.assertEqual(path, slow_au_file.path)
Exemple #8
0
def from_directory(dirpath, fast=False):
    """Creates Album objects from the files in a directory.

    Found audio files are grouped into albums based on their TALB tags.
    Non-audio files are silently ignored.

    Args:
      dirpath: The path to the directory to scan for audio files.
      fast: If True, do a fast scan when analyzing the audio files.

    Returns:
      A list of Album objects.
    """
    by_talb = {}
    for basename in os.listdir(dirpath):
        file_path = os.path.join(dirpath, basename)
        # Skip anything that isn't a regular file.
        if not os.path.isfile(file_path):
            continue
        # Skip dotfiles
        if basename.startswith("."):
            continue
        # Must have mp3 as the extension.
        if not basename.lower().endswith(".mp3"):
            continue
        if fast:
            au_file = audio_file.scan_fast(file_path)
        else:
            au_file = audio_file.scan(file_path)
        # Silently skip anything that seems bogus.
        if not au_file:
            continue
        if not "TALB" in au_file.mutagen_id3:
            raise AlbumError("Missing TALB tag on %s" % file_path)
        talb = au_file.mutagen_id3["TALB"].text[0]
        by_talb.setdefault(talb, []).append(au_file)

    return [Album(all_au_files) for all_au_files in by_talb.values()]
Exemple #9
0
def from_directory(dirpath, fast=False):
    """Creates Album objects from the files in a directory.

    Found audio files are grouped into albums based on their TALB tags.
    Non-audio files are silently ignored.

    Args:
      dirpath: The path to the directory to scan for audio files.
      fast: If True, do a fast scan when analyzing the audio files.

    Returns:
      A list of Album objects.
    """
    by_talb = {}
    for basename in os.listdir(dirpath):
        file_path = os.path.join(dirpath, basename)
        # Skip anything that isn't a regular file.
        if not os.path.isfile(file_path):
            continue
        # Skip dotfiles
        if basename.startswith("."):
            continue
        # Must have mp3 as the extension.
        if not basename.lower().endswith(".mp3"):
            continue
        if fast:
            au_file = audio_file.scan_fast(file_path)
        else:
            au_file = audio_file.scan(file_path)
        # Silently skip anything that seems bogus.
        if not au_file:
            continue
        if not "TALB" in au_file.mutagen_id3:
            raise AlbumError("Missing TALB tag on %s" % file_path)
        talb = au_file.mutagen_id3["TALB"].text[0]
        by_talb.setdefault(talb, []).append(au_file)

    return [Album(all_au_files) for all_au_files in by_talb.values()]
    def test_scan_fast_tag_handling(self):
        test_mp3 = mutagen.mp3.MP3()
        class MockInfo(object): pass
        test_mp3.info = MockInfo()
        test_mp3.add_tags()
        test_mp3.tags.add(ufid.ufid_tag(TEST_VOL, TEST_TS, TEST_FP))
        test_mp3.tags.add(mutagen.id3.TLEN(text=u"11111"))
        test_mp3.tags.add(mutagen.id3.TXXX(
                desc=constants.TXXX_ALBUM_ID_DESCRIPTION,
                text=[u"222"]))
        test_mp3.tags.add(mutagen.id3.TXXX(
                desc=constants.TXXX_FRAME_COUNT_DESCRIPTION,
                text=[u"333"]))
        test_mp3.tags.add(mutagen.id3.TXXX(
                desc=constants.TXXX_FRAME_SIZE_DESCRIPTION,
                text=["444"]))
        for tag in test_mp3.tags.values():
            id3_text.standardize(tag)
        test_mp3.info.sample_rate = 5555
        test_mp3.info.bitrate = 6666
        test_mp3.info.mode = 2

        au_file = audio_file.scan_fast("/test/path",
                                       _read_id3_hook=lambda p: test_mp3)
        self.assertTrue(audio_file is not None)
        self.assertEqual("/test/path", au_file.path)
        self.assertEqual(TEST_VOL, au_file.volume)
        self.assertEqual(TEST_TS, au_file.import_timestamp)
        self.assertEqual(TEST_FP, au_file.fingerprint)
        self.assertEqual(11111, au_file.duration_ms)
        self.assertEqual(222, au_file.album_id)
        self.assertEqual(333, au_file.frame_count)
        self.assertEqual(444, au_file.frame_size)
        self.assertEqual(5555, au_file.mp3_header.sampling_rate_hz)
        self.assertEqual(6.666, au_file.mp3_header.bit_rate_kbps)
        self.assertEqual(2, au_file.mp3_header.channels)
Exemple #11
0
    def __iter__(self):
        """Iterator that yields a sequence of crawled MP3s.

        Yields:
          An AudioFile object.
        """
        self._reset()

        yielded_size = 0
        for root_path in self._all_roots:
            for self._current_dir, dirnames, filenames in os.walk(root_path):

                # We do not recursively descend into these directoryies.
                dirnames[:] = self._remove_ignored_directories(
                    self._current_dir, dirnames)

                # If a directory filter has been specified, use it to know
                # when to silently skip any files in a single directory.
                if (self._directory_filter
                        and not self._directory_filter(self._current_dir)):
                    continue

                # Now walk across each file in this dir, yielding a
                # stream of AudioFile objects.
                for name in filenames:
                    full_path = os.path.join(self._current_dir, name)

                    # Skip files with the wrong sorts of names.  These are
                    # not logged.
                    if name.startswith("."):
                        continue

                    if not name.lower().endswith(".mp3"):
                        self.skipped_files.append(
                            (full_path, "Invalid filename"))
                        continue

                    # Stat the file, and skip the files when that
                    # operation fails.
                    try:
                        stat_obj = os.stat(full_path)
                    except (IOError, OSError), ex:
                        self.skipped_files.append((full_path, str(ex)))
                        continue

                    try:
                        if self._fast:
                            au_file = audio_file.scan_fast(full_path)
                        else:
                            au_file = audio_file.scan(full_path)
                    except Exception, ex:
                        # TODO(trow): Here we should really only catch
                        # the exceptions we expect audio_file.scan and
                        # .scan_fast to raise.
                        self.skipped_files.append((full_path, str(ex)))
                        logging.error("Skipping file %s: %s", full_path,
                                      str(ex))
                        continue

                    if au_file is None:
                        self.skipped_files.append(
                            (full_path, "Not an MP3 (No tags?)"))
                        continue

                    # Remember this directory, then yield the AudioFile.
                    self.directories_seen.add(self._current_dir)
                    yield au_file
Exemple #12
0
    def __iter__(self):
        """Iterator that yields a sequence of crawled MP3s.

        Yields:
          An AudioFile object.
        """
        self._reset()

        yielded_size = 0
        for root_path in self._all_roots:
            for self._current_dir, dirnames, filenames in os.walk(root_path):

                # We do not recursively descend into these directoryies.
                dirnames[:] = self._remove_ignored_directories(
                    self._current_dir, dirnames)

                # If a directory filter has been specified, use it to know
                # when to silently skip any files in a single directory.
                if (self._directory_filter
                    and not self._directory_filter(self._current_dir)):
                    continue

                # Now walk across each file in this dir, yielding a
                # stream of AudioFile objects.
                for name in filenames:
                    full_path = os.path.join(self._current_dir, name)

                    # Skip files with the wrong sorts of names.  These are
                    # not logged.
                    if name.startswith("."):
                        continue

                    if not name.lower().endswith(".mp3"):
                        self.skipped_files.append(
                            (full_path, "Invalid filename"))
                        continue
                    
                    # Stat the file, and skip the files when that
                    # operation fails.
                    try:
                        stat_obj = os.stat(full_path)
                    except (IOError, OSError), ex:
                        self.skipped_files.append((full_path, str(ex)))
                        continue

                    try:
                        if self._fast:
                            au_file = audio_file.scan_fast(full_path)
                        else:
                            au_file = audio_file.scan(full_path)
                    except Exception, ex:
                        # TODO(trow): Here we should really only catch
                        # the exceptions we expect audio_file.scan and
                        # .scan_fast to raise.
                        self.skipped_files.append((full_path, str(ex)))
                        logging.error("Skipping file %s: %s",
                                      full_path, str(ex))
                        continue

                    if au_file is None:
                        self.skipped_files.append((full_path,
                                                   "Not an MP3 (No tags?)"))
                        continue

                    # Remember this directory, then yield the AudioFile.
                    self.directories_seen.add(self._current_dir)
                    yield au_file