Example #1
0
def Scan(path, files, mediaList, subdirs, language=None, root=None):
    """Handle .cue files.
   Find any Cue files in the input list. Remove any files handled by the Cue
   file. Handle any remaining files normally.
   """
    FLACCueParse(path, files, mediaList, subdirs, language=language, root=root)

    # Scan for other audio files, including those that failed to process correctly.
    AudioFiles.Scan(path, files, mediaList, subdirs, root=root)

    # Read tags, etc. and build up the mediaList
    AudioFiles.Process(path,
                       files,
                       mediaList,
                       subdirs,
                       language=language,
                       root=root)
def Scan(path, files, mediaList, subdirs, language=None, root=None):
  if len(path) == 0:

    # Top level, albums.
    dom = minidom.parse(urllib.urlopen('http://127.0.0.1:32400/music/iTunes/Albums'))
    for album in sorted(dom.getElementsByTagName('Album'), key=lambda album: album.getAttribute('artist').lower() + album.getAttribute('album').lower()):

      # Tracks.
      path = album.getAttribute('key')
      dom = minidom.parse(urllib.urlopen('http://127.0.0.1:32400/music/iTunes/Albums/%s' % path))
      artist_album_map = {}
      compilation_count = 0
      
      for track in dom.getElementsByTagName('Track'):

        # Figure out album artist.
        album_artist = track.getAttribute('albumArtist').strip()
        artist_album_map[album_artist] = True
        if len(album_artist) == 0: album_artist = None
        else: album_artist = album_artist.encode('utf-8')

        # Compilation handling.
        if track.getAttribute('compilation') == '1': 
          album_artist = 'Various Artists' 
          title = track.getAttribute('artist').encode('utf-8') + ' - ' + track.getAttribute('track').encode('utf-8')
        else: 
          title = track.getAttribute('track').encode('utf-8')   

        # Track index.
        index = int(track.getAttribute('index'))
        path = AudioFiles.cleanPass(track.getAttribute('file'))
        if index == 0:
          try: index = int(re.findall('[.\-]+[ ]*([0-9]{2})[ ]*[.\-]', os.path.basename(path))[0])
          except: 
            try: index = int(re.findall('^([0-9]{2})[ .\-]', os.path.basename(path))[0])
            except: pass

        # Add the track.
        t = Media.Track(artist = track.getAttribute('artist').encode('utf-8'),
                        album = track.getAttribute('album').encode('utf-8'),
                        title = track.getAttribute('track').encode('utf-8'),
                        index = index,
                        album_artist = album_artist,
                        disc = int(track.getAttribute('disc')))
        t.parts.append(urllib.unquote(path))
        mediaList.append(t)
def Scan(path, files, media_list, subdirs, language=None, root=None, respect_tags=False):

  # Scan for audio files.
  AudioFiles.Scan(path, files, media_list, subdirs, root)
  
  root_str = root or ''
  loc_str = os.path.join(root_str, path)
  Log('Scanning: ' + loc_str)
  Log('Files: ' + str(files))
  Log('Subdirs: ' + str(subdirs))

  # Look at the files and determine whether we can do a quick match (minimal tag parsing).
  do_quick_match = True
  mixed = False

  # Make sure we're looking at a leaf directory (no audio files below here).
  if len(subdirs) > 0:
    Log('Found directories below this one; won\'t attempt quick matching.')
    do_quick_match = False

  if files:

    # Make sure we're not sitting in the section root.
    parent_path = os.path.split(files[0])[0]
    if parent_path == root:
      Log('File(s) are in section root; doing expensive matching with mixed content.')
      do_quick_match = False
      mixed = True

    # Make sure we have reliable track indices for all files and there are no dupes.
    tracks = {}
    for f in files:
      try: 
        index = re.search(r'^([0-9]{1,2})[^0-9].*', os.path.split(f)[-1]).groups(0)[0]
      except:
        do_quick_match = False
        Log('Couldn\'t find track indices in all filenames; doing expensive matching.')
        break
      if tracks.get(index):
        do_quick_match = False
        mixed = True
        Log('Found duplicate track index: %s; doing expensive matching with mixed content.' % index)
        break
      else:
        tracks[index] = True

    # Read the first track's tags to check for milti-disc and VA.
    if do_quick_match:
      disc = album_artist = None
      try:
        (artist, album, title, track, disc, album_artist, compil) = AudioFiles.getInfoFromTag(files[0], language)
      except:
        Log('Exception reading tags from first file; doing expensive matching.')
        do_quick_match = False

      # Make sure we are on the first disc.
      if disc is not None and disc > 1:
        Log('Skipping quick match because of non-first disc.')
        do_quick_match = False

      # We want to read all the tags for VA albums to pick up track artists.
      if album_artist is not None and album_artist == 'Various Artists':
        Log('Skipping quick match for Various Artists album.')      
        do_quick_match = False

    artist = None
    album = None

    if do_quick_match:
      Log('Doing quick match')
      
      # See if we have some consensus on artist/album by reading a few tags.
      for i in range(3):
        if i < len(files):
          this_artist = this_album = tags = None
          try: tags = mutagen.File(files[i], easy=True)
          except: Log('There was an exception thrown reading tags.')
          
          if tags:
            # See if there's an album artist tag.
            album_artist_tags = [t for t in ['albumartist', 'TPE2', 'performer'] if t in tags]
            album_artist_tag = album_artist_tags[0] if len(album_artist_tags) else None
            
            this_artist = tags[album_artist_tag][0] if album_artist_tag else tags['artist'][0] if 'artist' in tags else None
            this_album = tags['album'][0] if 'album' in tags else None

          if artist and artist != this_artist:
            Log('Found different artists in tags (%s vs. %s); doing expensive matching.' % (artist, this_artist))
            do_quick_match = False
            break

          if album and album != this_album:
            Log('Found different albums in tags (%s vs. %s); doing expensive matching.' % (artist, this_artist))
            do_quick_match = False
            break

          artist = this_artist
          album = this_album
      
      if not artist or not album:
        Log('Couldn\'t determine unique artist or album from tags; doing expensive matching.')
        do_quick_match = False

    query_list = []
    result_list = []
    fingerprint = False

    # Directory looks clean, let's build a query list directly from info gleaned from file names.
    if do_quick_match:
      Log('Building query list for quickmatch with artist: %s, album: %s' % (artist, album))

      # Determine if the artist and/or album appears in all filenames, since we'll want to strip these out for clean titles.
      strip_artist = True if len([f for f in files if artist.lower() in Unicodize(os.path.basename(f), language).lower()]) == len(files) else False
      strip_album = True if len([f for f in files if album.lower() in Unicodize(os.path.basename(f), language).lower()]) == len(files) else False

      for f in files:
        try:
          filename = os.path.splitext(os.path.split(f)[1])[0]
          (head, index, title) = re.split(r'^([0-9]{1,2})', filename)

          # Replace underscores and dots with spaces.
          title = re.sub(r'[_\. ]+', ' ', title)

          # Things in parens seem to confuse Gracenote, so let's strip them out.
          title = re.sub(r' ?\(.*\)', '', title)

          # Remove artist name from title if it appears in all of them.
          if strip_artist and len(files) > 2:
            title = re.sub(r'(?i)' + artist, '', title)

          # Remove album title from title if it appears in all of them.
          if strip_album and len(files) > 2:
            title = re.sub(r'(?i)' + album, '', title)

          # Remove any remaining index-, artist-, and album-related cruft from the head of the track title.
          title = re.sub(r'^[\W\-]+', '', title).strip()

          # Last chance for artist or album prefix.
          if not strip_artist and Unicodize(title, language).lower().find(artist.lower()) == 0:
            title = title[len(artist):]
            
          if not strip_album and Unicodize(title, language).lower().find(album.lower()) == 0:
            title = title[len(album):]
      
          t = Media.Track(artist=toBytes(artist), album=toBytes(album), title=toBytes(title), index=int(index))
          t.parts.append(f)

          Log(' - Adding: %s - %s' % (index, title))
          query_list.append(t)

        except Exception as e:
          Log('Error preparing tracks for quick matching: ' + str(e))

    # Otherwise, let's do old school directory crawling and tag reading.
    else:
      AudioFiles.Process(path, files, media_list, subdirs, root)
      query_list = list(media_list)
    
    # Try as-is first (ask for everything at once).
    discs = [query_list]
    final_match = run_queries(discs, result_list, language, fingerprint, mixed, do_quick_match)
    
    # If the match was still shitty, and it looks like we have multiple discs, try splitting.
    if final_match < 75:
      discs = group_tracks_by_disc(query_list)
      if len(discs) > 1:
        Log('Result still looked bad, we will try splitting into separate per-disc queries.')
        other_result_list = []
        other_match = run_queries(discs, other_result_list, language, fingerprint, mixed, do_quick_match)
        
        if other_match > final_match:
          Log('The split result was best, we will use it.')
          result_list = other_result_list
          final_match = other_match
        
    # If we have a crappy match, don't use it.
    if final_match < 50.0:
      Log('That was terrible, let us not use it.')
      result_list = []

    # Finalize the results.
    used_tags = False
    del media_list[:]
    if len(result_list) > 0:
      # Gracenote results.
      for result in result_list:
        media_list.append(result)
    else:
      # We bailed during the GN lookup, fall back to tags.
      used_tags = True
      AudioFiles.Process(path, files, media_list, subdirs, root)

    # If we wanted to respect tags, then make sure we used tags.
    if not used_tags and respect_tags:

      # Let's grab tag results, and then set GUIDs we found.
      tag_media_list = []
      AudioFiles.Process(path, files, tag_media_list, subdirs, root)
      
      # Now suck GN data out.
      path_map = {}
      for track in media_list:
        path_map[track.parts[0]] = track
        
      for track in tag_media_list:
        if track.parts[0] in path_map:
          gn_track = path_map[track.parts[0]]
          track.guid = gn_track.guid
          track.album_guid = gn_track.album_guid
          track.artist_guid = gn_track.artist_guid
          track.album_thumb_url = gn_track.album_thumb_url
          track.artist_thumb_url = gn_track.artist_thumb_url
          
          # If the tags failed, fill in key data from Gracenote.
          if track.album == '[Unknown Album]':
            track.album = gn_track.album
          
          if track.artist == '[Unknown Artist]':
            track.artist = gn_track.artist
      
      media_list[:] = tag_media_list
Example #4
0
def Scan(path, files, mediaList, subdirs, language=None, root=None):
   """Handle FLAC with Cue.
   Find any Cue files in the input list.
   """
   cues = []
   for f in files:
      if(os.path.splitext(f)[1] == '.cue'):
         cues.append(f)
   for cue in cues:
      log(cue)
      try:
         # Get the Cue sheet info.
         info = read_cue(cue)
         log(info)
         # Get all files mentioned in the Cue sheet.
         cuefiles = info['Files']
         # Get the directory the files should be in. This should be
         # the same as the Cue sheet directory.
         folder = os.path.dirname(cue)
         for file in cuefiles:
            # Get the full FLAC file path.
            full_file = os.path.join(folder, file)

            # My FLAC files include "Disc 1", "Disc 2", and similar as the
            # final part of the title for multi-disk sets. Something like:
            # "Artist - Album Title Disc 3.flac"
            # The scanner is designed to pull disc information from this
            # and to group albums together.

            # Get the name of the FLAC file without the extension.
            # Split it for white space.
            try:
               flac_details = os.path.splitext(file)[-2].split()
               # Check for disc numbering.
               if(flac_details[-2] == 'Disc'):
                  disc = int(flac_details[-1])
               else:
                  disc = 1
            except IndexError:
               disc = 1

            try:
               # Add the full FLAC file.
               # Number it as track -1.
               track = -1
               # Get the file info for the full FLAC file.
               flac_info = mutagen.flac.FLAC(full_file)
               # Add the additional disc number information.
               flac_info['discnumber'] = ['{0:0d}'.format(disc)]
               # Make this track -1.
               flac_info['tracknumber'] = ['{0:02d}'.format(track)]
               # Call this "Album Name - Full Album" in the track listing
               # Ensure the info is added cleanly.
               if('artist' not in flac_info or flac_info['artist'][0] == ''):
                  flac_info['artist'] = [info['PERFORMER']]
               if('album' not in flac_info or flac_info['album'][0] == ''):
                  flac_info['album'] = [info['TITLE']]
               if('albumartist' not in flac_info or flac_info['albumartist'][0] == ''):
                  flac_info['albumartist'] = [info['PERFORMER']]
               flac_info['title'] = ['{0} - Full album'.format(flac_info['album'][0])]
               artist = AudioFiles.cleanPass(flac_info['artist'][0])
               album = AudioFiles.cleanPass(flac_info['album'][0])
               title = AudioFiles.cleanPass(flac_info['title'][0])
               album_artist = AudioFiles.cleanPass(flac_info['albumartist'][0])
               # Create the track object.
               track_object = Media.Track(artist, album, title, track,
                                          disc=disc, album_artist=album_artist,
                                          guid=None, album_guid=None)
               # Use the FLAC file for playback.
               track_object.parts.append(full_file)
               log(track_object)
               # Add the track object to the output list.
               mediaList.append(track_object)
               
               # Split into tracks.
               track_info = cuefiles[file]['Tracks']
               start_time = '00:00:00'
               end_time = '00:00:00'
               # Handle each track.
               for track in track_info:
                  title = AudioFiles.cleanPass(track_info[track]['TITLE'])
                  try:
                     # Get the start time of the track.
                     start_time = track_info[track]['INDEX'][1]
                  except KeyError:
                     # If none is listed, use the previous end time.
                     start_time = end_time
                  try:
                     # Get the start time of the following track.
                     # Use this as the end time for the current track.
                     end_time = track_info[track+1]['INDEX'][1]
                  except (IndexError, KeyError):
                     # For the last track, we just take the end time of the
                     # FLAC file as the end of the song.
                     file_end = flac_info.info.length
                     minutes = int(file_end / 60)
                     seconds = int(file_end % 60)
                     # 75 frames per second.
                     frames = int(round(75 * (file_end % 1)))
                     end_time = '{0:02d}:{1:02d}:{2:02d}'.format(minutes, seconds, frames)
                  # Create the track object.
                  track_object = Media.Track(artist, album, title, track,
                                             disc=disc, album_artist=album_artist,
                                             guid=None, album_guid=None)
                  # Use a file format for compatibility with the FLACCue
                  # FUSE (Filesystem in Userspace) code.
                  # This will be something like:
                  # /flaccue/Music/Artist/Album/Artist - Album Disc 1.flac.10:25:17.12:55:20
                  track_object.parts.append('/flaccue'+full_file+'.{0}.{1}'.format(start_time, end_time))
                  log(track_object)
                  # Add the track to the returned object list.
                  mediaList.append(track_object)
               log('')
               # Remove the FLAC file from the list to parse.
               files.remove(full_file)
            except:
               log(traceback.format_exc())
      except:
         log(traceback.format_exc())
      finally:
         files.remove(cue)

   # Scan for other audio files, including those that failed to process correctly.
   AudioFiles.Scan(path, files, mediaList, subdirs, root=root)

   # Read tags, etc. and build up the mediaList
   AudioFiles.Process(path, files, mediaList, subdirs, language=language, root=root)
Example #5
0
def read_cue(file):
   """Parse the Cue sheet to get the desired info.
   """
   # Read the full Cue file.
   with open(file, 'r') as f:
      lines = f.readlines()
   cue = {}
   cue['Files'] = {}
   # Line index. We don't use a for loop as we will
   # read multiple lines for information.
   i = 0
   lenlines = len(lines)
   try:
      while(True):
         # We have a FILE specification in the Cue sheet.
         if(lines[i].startswith('FILE')):
            # Get the filename.
            filename = AudioFiles.cleanPass(lines[i].split('"')[1])
            # Now we will parse the tracks from the file.
            # Use a local variable name for clarity.
            file_details = {}
            # But store that variable in the cue sheet parse dictionary.
            cue['Files'][filename] = file_details
            # Create the Track entry to store tracks from the file.
            file_details['Tracks'] = {}
            # Start at the next line.
            i += 1
            # Use the Cue sheet indentation for sectioning. 2 spaces for
            # TRACK entries in the FILE entry.
            while(lines[i].startswith(' '*2)):
               # Get rid of extra white space.
               line = lines[i].strip()
               # Handle TRACK entries.
               if(line.startswith('TRACK')):
                  # Get the track number.
                  track = int(line.split()[1])
                  # Use a local variable name for clarity.
                  track_details = {}
                  # But store that variable in the cue sheet parse dictionary.
                  file_details['Tracks'][track] = track_details
                  # Create the INDEX dictionary to store track indices.
                  track_details['INDEX'] = {}
                  # Start at the next line.
                  i += 1
                  # Use the Cue sheet indentation for sectioning. 4 spaces
                  # for INDEX entries in the TRACK entry.
                  while(lines[i].startswith(' '*4)):
                     # Get rid of extra white space.
                     line = lines[i].strip()
                     # Find the index entries.
                     if(line.startswith('INDEX')):
                        # Remove the INDEX text and extra white space.
                        line = line[5:].strip()
                        # Get the INDEX number and the rest of the line.
                        # The rest of the line should be the time information.
                        key, value = line.split(None, 1)
                        # Store the time information for this index.
                        track_details['INDEX'][int(key)] = value.strip().replace('"', '')
                        i += 1
                     else:
                        # Store all the other entries as text. Use the first
                        # word as the access key.
                        key, value = line.split(None, 1)
                        # Also remove quotes from track names and similar.
                        track_details[key] = value.strip().replace('"', '')
                        i += 1
               else:
                  # Store all the other entries as text. Use the first
                  # word as the access key.
                  key, value = lines[i].split(None, 1)
                  # Also remove quotes from track names and similar.
                  file_details[key] = value.strip().replace('"', '')
                  i += 1
         else:
            # Store all the other entries as text. Use the first
            # word as the access key.
            key, value = lines[i].split(None, 1)
            # Also remove quotes from track names and similar.
            cue[key] = value.strip().replace('"', '')
            i += 1
   except IndexError:
      # We're done.
      pass
   return cue
Example #6
0
def Scan(path,
         files,
         media_list,
         subdirs,
         language=None,
         root=None,
         respect_tags=False):

    # Scan for audio files.
    AudioFiles.Scan(path, files, media_list, subdirs, root)

    root_str = root or ''
    loc_str = os.path.join(root_str, path)
    Log('Scanning: ' + loc_str)
    Log('Files: ' + str(files))
    Log('Subdirs: ' + str(subdirs))

    # Look at the files and determine whether we can do a quick match (minimal tag parsing).
    do_quick_match = True
    mixed = False

    # Make sure we're looking at a leaf directory (no audio files below here).
    if len(subdirs) > 0:
        Log('Found directories below this one; won\'t attempt quick matching.')
        do_quick_match = False

    if files:

        # Make sure we're not sitting in the section root.
        parent_path = os.path.split(files[0])[0]
        if parent_path == root:
            Log('File(s) are in section root; doing expensive matching with mixed content.'
                )
            do_quick_match = False
            mixed = True

        # Make sure we have reliable track indices for all files and there are no dupes.
        tracks = {}
        for f in files:
            try:
                index = re.search(r'^([0-9]{1,2})[^0-9].*',
                                  os.path.split(f)[-1]).groups(0)[0]
            except:
                do_quick_match = False
                Log('Couldn\'t find track indices in all filenames; doing expensive matching.'
                    )
                break
            if tracks.get(index):
                do_quick_match = False
                mixed = True
                Log('Found duplicate track index: %s; doing expensive matching with mixed content.'
                    % index)
                break
            else:
                tracks[index] = True

        # Read the first track's tags to check for milti-disc and VA.
        if do_quick_match:
            disc = album_artist = None
            try:
                (artist, album, title, track, disc, album_artist,
                 compil) = AudioFiles.getInfoFromTag(files[0], language)
            except:
                Log('Exception reading tags from first file; doing expensive matching.'
                    )
                do_quick_match = False

            # Make sure we are on the first disc.
            if disc is not None and disc > 1:
                Log('Skipping quick match because of non-first disc.')
                do_quick_match = False

            # We want to read all the tags for VA albums to pick up track artists.
            if album_artist is not None and album_artist == 'Various Artists':
                Log('Skipping quick match for Various Artists album.')
                do_quick_match = False

        artist = None
        album = None

        if do_quick_match:
            Log('Doing quick match')

            # See if we have some consensus on artist/album by reading a few tags.
            for i in range(3):
                if i < len(files):
                    this_artist = this_album = tags = None
                    try:
                        tags = mutagen.File(files[i], easy=True)
                    except:
                        Log('There was an exception thrown reading tags.')

                    if tags:
                        # See if there's an album artist tag.
                        album_artist_tags = [
                            t for t in ['albumartist', 'TPE2', 'performer']
                            if t in tags
                        ]
                        album_artist_tag = album_artist_tags[0] if len(
                            album_artist_tags) else None

                        this_artist = tags[album_artist_tag][
                            0] if album_artist_tag else tags['artist'][
                                0] if 'artist' in tags else None
                        this_album = tags['album'][
                            0] if 'album' in tags else None

                    if artist and artist != this_artist:
                        Log('Found different artists in tags (%s vs. %s); doing expensive matching.'
                            % (artist, this_artist))
                        do_quick_match = False
                        break

                    if album and album != this_album:
                        Log('Found different albums in tags (%s vs. %s); doing expensive matching.'
                            % (album, this_album))
                        do_quick_match = False
                        break

                    artist = this_artist
                    album = this_album

            if not artist or not album:
                Log('Couldn\'t determine unique artist or album from tags; doing expensive matching.'
                    )
                do_quick_match = False

        query_list = []
        result_list = []
        fingerprint = False

        # Directory looks clean, let's build a query list directly from info gleaned from file names.
        if do_quick_match:
            Log('Building query list for quickmatch with artist: %s, album: %s'
                % (artist, album))

            # Determine if the artist and/or album appears in all filenames, since we'll want to strip these out for clean titles.
            strip_artist = True if len([
                f for f in files if artist.lower() in Unicodize(
                    os.path.basename(f), language).lower()
            ]) == len(files) else False
            strip_album = True if len([
                f for f in files if album.lower() in Unicodize(
                    os.path.basename(f), language).lower()
            ]) == len(files) else False

            for f in files:
                try:
                    filename = os.path.splitext(os.path.split(f)[1])[0]
                    (head, index, title) = re.split(r'^([0-9]{1,2})', filename)

                    # Replace underscores and dots with spaces.
                    title = re.sub(r'[_\. ]+', ' ', title)

                    # Things in parens seem to confuse Gracenote, so let's strip them out.
                    title = re.sub(r' ?\(.*\)', '', title)

                    # Remove artist name from title if it appears in all of them.
                    if strip_artist and len(files) > 2:
                        title = re.sub(r'(?i)' + artist, '', title)

                    # Remove album title from title if it appears in all of them.
                    if strip_album and len(files) > 2:
                        title = re.sub(r'(?i)' + album, '', title)

                    # Remove any remaining index-, artist-, and album-related cruft from the head of the track title.
                    title = re.sub(r'^[\W\-]+', '', title).strip()

                    # Last chance for artist or album prefix.
                    if not strip_artist and Unicodize(
                            title, language).lower().find(artist.lower()) == 0:
                        title = title[len(artist):]

                    if not strip_album and Unicodize(
                            title, language).lower().find(album.lower()) == 0:
                        title = title[len(album):]

                    t = Media.Track(artist=toBytes(artist),
                                    album=toBytes(album),
                                    title=toBytes(title),
                                    index=int(index))
                    t.parts.append(f)

                    Log(' - Adding: %s - %s' % (index, title))
                    query_list.append(t)

                except Exception as e:
                    Log('Error preparing tracks for quick matching: ' + str(e))

        # Otherwise, let's do old school directory crawling and tag reading.
        else:
            AudioFiles.Process(path, files, media_list, subdirs, root)
            query_list = list(media_list)

        # Try as-is first (ask for everything at once).
        discs = [query_list]
        final_match = run_queries(discs, result_list, language, fingerprint,
                                  mixed, do_quick_match)

        # If the match was still shitty, and it looks like we have multiple discs, try splitting.
        if final_match < 75:
            discs = group_tracks_by_disc(query_list)
            if len(discs) > 1:
                Log('Result still looked bad, we will try splitting into separate per-disc queries.'
                    )
                other_result_list = []
                other_match = run_queries(discs, other_result_list, language,
                                          fingerprint, mixed, do_quick_match)

                if other_match > final_match:
                    Log('The split result was best, we will use it.')
                    result_list = other_result_list
                    final_match = other_match

        # If we have a crappy match, don't use it.
        if final_match < 50.0:
            Log('That was terrible, let us not use it.')
            result_list = []

        # Finalize the results.
        used_tags = False
        del media_list[:]
        if len(result_list) > 0:
            # Gracenote results.
            for result in result_list:
                media_list.append(result)
        else:
            # We bailed during the GN lookup, fall back to tags.
            used_tags = True
            AudioFiles.Process(path, files, media_list, subdirs, root)

        # If we wanted to respect tags, then make sure we used tags.
        if not used_tags and respect_tags:

            # Let's grab tag results, and then set GUIDs we found.
            tag_media_list = []
            AudioFiles.Process(path, files, tag_media_list, subdirs, root)

            # Now suck GN data out.
            path_map = {}
            for track in media_list:
                path_map[track.parts[0]] = track

            for track in tag_media_list:
                if track.parts[0] in path_map:
                    gn_track = path_map[track.parts[0]]
                    track.guid = gn_track.guid
                    track.album_guid = gn_track.album_guid
                    track.artist_guid = gn_track.artist_guid
                    track.album_thumb_url = gn_track.album_thumb_url
                    track.artist_thumb_url = gn_track.artist_thumb_url

                    # If the tags failed, fill in key data from Gracenote.
                    if track.album == '[Unknown Album]':
                        track.album = gn_track.album

                    if track.artist == '[Unknown Artist]':
                        track.artist = gn_track.artist

            media_list[:] = tag_media_list
Example #7
0
def FLACCueParse(path, files, mediaList, subdirs, language=None, root=None):
    cues = []
    for f in files:
        if (os.path.splitext(f)[1] == '.cue'):
            cues.append(f)
    for cue in cues:
        log(cue)
        try:
            # Get the Cue sheet info.
            info = read_cue(cue)
            log(info)
            # Get all files mentioned in the Cue sheet.
            cuefiles = info['Files']
            # Get the album information.
            album = info['TITLE']
            album_artist = AudioFiles.cleanPass(info['PERFORMER'])
            if (album_artist == ''):
                # No listed album artist. Use the artist from the first
                # track of the first file.
                try:
                    first_file = list(cuefiles.keys())[0]
                    album_artist = cuefiles[first_file]['Tracks'][1][
                        'PERFORMER']
                except KeyError:
                    album_artist = 'Unknown'
            # Get the directory the files should be in. This should be
            # the same as the Cue sheet directory.
            folder = os.path.dirname(cue)
            for file in cuefiles:
                # Get the full file path.
                full_file = os.path.join(folder, file)
                if (not os.path.exists(full_file)):
                    continue

                # My cue files include "Disc 1", "Disc 2", and similar as the
                # final part of the title for multi-disk sets. Something like:
                # "Artist - Album Title Disc 3.cue"
                # The scanner is designed to pull disc information from this
                # and to group albums together.

                # Get the name of the cue file without the extension.
                # Split it for white space.
                try:
                    file_details = os.path.splitext(file)[-2].split()
                    # Check for disc numbering.
                    if (file_details[-2] == 'Disc'):
                        disc = int(file_details[-1])
                    else:
                        disc = 1
                except IndexError:
                    disc = 1

                try:
                    # Add the full file.
                    # Number it as track -1.
                    track = -1
                    # Call this "Album Name - Disc #" in the track listing
                    # Ensure the info is added cleanly.
                    title = '{0} - Disc {1}'.format(album, disc)
                    title = AudioFiles.cleanPass(title)
                    artist = AudioFiles.cleanPass(album_artist)
                    # Create the track object.
                    # Use disc 9999 to group all the full discs together. Use
                    # the disc number as the track number.
                    track_object = Media.Track(artist,
                                               album,
                                               title,
                                               disc,
                                               disc=9999,
                                               album_artist=album_artist,
                                               guid=None,
                                               album_guid=None)
                    # Use the file for playback.
                    track_object.parts.append(full_file)
                    log(track_object)
                    # Add the track object to the output list.
                    mediaList.append(track_object)

                    # Split into tracks.
                    track_info = cuefiles[file]['Tracks']
                    start_time = '00:00:00'
                    end_time = '00:00:00'
                    # Handle each track.
                    for track in track_info:
                        title = AudioFiles.cleanPass(
                            track_info[track]['TITLE'])
                        try:
                            artist = AudioFiles.cleanPass(
                                track_info[track]['PERFORMER'])
                        except KeyError:
                            # No track artist specified. Use the album artist.
                            artist = album_artist
                        try:
                            # Get the start time of the track.
                            start_time = track_info[track]['INDEX'][1]
                        except KeyError:
                            # If none is listed, use the previous end time.
                            start_time = end_time
                        try:
                            # Get the start time of the following track.
                            # Use this as the end time for the current track.
                            end_time = track_info[track + 1]['INDEX'][1]
                        except (IndexError, KeyError):
                            # For the last track, we specify -1 to indicate the end of file.
                            end_time = '-1'
                        # Create the track object.
                        track_object = Media.Track(artist,
                                                   album,
                                                   title,
                                                   track,
                                                   disc=disc,
                                                   album_artist=album_artist,
                                                   guid=None,
                                                   album_guid=None)
                        # Use a file format for compatibility with the FLACCue
                        # FUSE (Filesystem in Userspace) code.
                        # This will be something like:
                        # /flaccue/Music/Artist/Album/Artist - Album Disc 1.flaccuesplit.10:25:17.12:55:20.flac
                        parsed_filename = '/flaccue' + full_file
                        extension = os.path.splitext(parsed_filename)[1]
                        parsed_filename = parsed_filename.replace(
                            extension, '.flaccuesplit.{0}.{1}{2}'.format(
                                start_time, end_time, extension))
                        track_object.parts.append(parsed_filename)
                        log(track_object)
                        # Add the track to the returned object list.
                        mediaList.append(track_object)
                    log('')
                    # Remove the FLAC file from the list to parse.
                    files.remove(full_file)
                except:
                    log(traceback.format_exc())
        except:
            log(traceback.format_exc())
        finally:
            files.remove(cue)
def Scan(path, files, mediaList, subdirs, language=None, root=None):

    # Scan for audio files.
    AudioFiles.Scan(path, files, mediaList, subdirs, root)
    if len(files) < 1: return
    albumTracks = []
    for f in files:
        try:
            artist = None
            (artist, album, title, track, disc, album_artist,
             compil) = getInfoFromTag(f, language)
            #print 'artist: ', artist, ' | album_artist: ', album_artist, ' | album: ', album, ' | disc: ', str(disc), ' | title: ', title, ' | compilation: ' + str(compil)
            if album_artist and album_artist.lower(
            ) in various_artists:  #(compil == '1' and (album_artist is None or len(album_artist.strip()) == 0)) or (
                album_artist = 'Various Artists'
            if artist == None or len(artist.strip()) == 0:
                artist = '[Unknown Artist]'
            if album == None or len(album.strip()) == 0:
                album = '[Unknown Album]'
            if title == None or len(
                    title) == 0:  #use the filename for the title
                title = os.path.splitext(os.path.split(f)[1])[0]

            if track == None:
                # See if we have a tracknumber in the title; if so, extract and strip it.
                m = re.match("^([0-9]{1,3})[ .-]+(.*)$", title)
                if m:
                    track, title = int(m.group(1)), m.group(2)
            else:
                # Check to see if the title starts with the track number and whack it.
                title = re.sub("^[ 0]*%s[ ]+" % track, '', title)

            title = title.strip(' -.')

            (allbutParentDir, parentDir) = os.path.split(os.path.dirname(f))
            if title.count(
                    ' - '
            ) == 1 and artist == '[Unknown Artist]':  # see if we can parse the title for artist - title
                (artist, title) = title.split(' - ')
                if len(artist) == 0: artist = '[Unknown Artist]'
            elif parentDir and parentDir.count(' - ') == 1 and (
                    artist == '[Unknown Artist]' or album == '[Unknown Album]'
            ):  #see if we can parse the folder dir for artist - album
                (pathArtist, pathAlbum) = parentDir.split(' - ')
                if artist == '[Unknown Artist]': artist = pathArtist
                if album == '[Unknown Album]': album = pathAlbum

            #make sure our last move is to encode to utf-8 before handing text back.
            t = Media.Track(cleanPass(artist),
                            cleanPass(album),
                            cleanPass(title),
                            track,
                            disc=disc,
                            album_artist=cleanPass(album_artist))
            t.parts.append(f)
            albumTracks.append(t)
            #print 'Adding: [Artist: ' + artist + '] [Album: ' + album + '] [Title: ' + title + '] [Tracknumber: ' + str(track) + '] [Disk: ' + str(disc) + '] [Album Artist: ' + album_artist + '] [File: ' + f + ']'
        except:
            pass
            #print "Skipping (Metadata tag issue): ", f

    #add all tracks in dir, but first see if this might be a Various Artist album
    #first, let's group the albums in this folder together
    albumsDict = {}
    artistDict = {}
    for t in albumTracks:
        #add all the album names to a dictionary
        if albumsDict.has_key(t.album.lower()):
            albumsDict[t.album.lower()].append(t)
        else:
            albumsDict[t.album.lower()] = [t]
        #count instances of same artist names
        if artistDict.has_key(t.artist):
            artistDict[t.artist] += 1
        else:
            artistDict[t.artist] = 1

    try:
        (maxArtistName, maxArtistCount) = sorted(artistDict.items(),
                                                 key=lambda (k, v): (v, k))[-1]
    except:
        maxArtistCount = 0

    percentSameArtist = float(maxArtistCount) / len(albumTracks)

    #next, iterate through the album keys, and look at the tracks inside each album
    for a in albumsDict.keys():
        sameAlbum = True
        sameArtist = True
        prevAlbum = None
        prevArtist = None
        blankAlbumArtist = True
        for t in albumsDict[a]:
            if prevAlbum == None: prevAlbum = t.album
            if prevArtist == None: prevArtist = t.artist
            if prevAlbum.lower() != t.album.lower(): sameAlbum = False
            if prevArtist.lower() != t.artist.lower(): sameArtist = False
            prevAlbum = t.album
            prevArtist = t.artist
            if t.album_artist and len(t.album_artist.strip()) > 0:
                blankAlbumArtist = False

        if sameAlbum == True and sameArtist == False and blankAlbumArtist:
            if percentSameArtist < .9:  #if the number of the same artist is less than X%, let's VA it (else, let's use the most common artist)
                newArtist = 'Various Artists'
            else:
                newArtist = maxArtistName
            for tt in albumsDict[a]:
                tt.album_artist = newArtist

    for t in albumTracks:
        mediaList.append(t)
    return
Example #9
0
def Scan(path, files, mediaList, subdirs, language=None, root=None):
    # Scan for audio files.
    AudioFiles.Scan(path, files, mediaList, subdirs, root)

    # Read tags, etc. and build up the mediaList
    AudioFiles.Process(path, files, mediaList, subdirs, root)