1# -*- coding: utf-8 -*-
2# This file is part of beets.
3# Copyright 2016, Adrian Sampson.
4#
5# Permission is hereby granted, free of charge, to any person obtaining
6# a copy of this software and associated documentation files (the
7# "Software"), to deal in the Software without restriction, including
8# without limitation the rights to use, copy, modify, merge, publish,
9# distribute, sublicense, and/or sell copies of the Software, and to
10# permit persons to whom the Software is furnished to do so, subject to
11# the following conditions:
12#
13# The above copyright notice and this permission notice shall be
14# included in all copies or substantial portions of the Software.
15
16"""Facilities for automatically determining files' correct metadata.
17"""
18
19from __future__ import division, absolute_import, print_function
20
21from beets import logging
22from beets import config
23
24# Parts of external interface.
25from .hooks import AlbumInfo, TrackInfo, AlbumMatch, TrackMatch  # noqa
26from .match import tag_item, tag_album, Proposal  # noqa
27from .match import Recommendation  # noqa
28
29# Global logger.
30log = logging.getLogger('beets')
31
32
33# Additional utilities for the main interface.
34
35def apply_item_metadata(item, track_info):
36    """Set an item's metadata from its matched TrackInfo object.
37    """
38    item.artist = track_info.artist
39    item.artist_sort = track_info.artist_sort
40    item.artist_credit = track_info.artist_credit
41    item.title = track_info.title
42    item.mb_trackid = track_info.track_id
43    item.mb_releasetrackid = track_info.release_track_id
44    if track_info.artist_id:
45        item.mb_artistid = track_info.artist_id
46    if track_info.data_source:
47        item.data_source = track_info.data_source
48
49    if track_info.lyricist is not None:
50        item.lyricist = track_info.lyricist
51    if track_info.composer is not None:
52        item.composer = track_info.composer
53    if track_info.composer_sort is not None:
54        item.composer_sort = track_info.composer_sort
55    if track_info.arranger is not None:
56        item.arranger = track_info.arranger
57
58    # At the moment, the other metadata is left intact (including album
59    # and track number). Perhaps these should be emptied?
60
61
62def apply_metadata(album_info, mapping):
63    """Set the items' metadata to match an AlbumInfo object using a
64    mapping from Items to TrackInfo objects.
65    """
66    for item, track_info in mapping.items():
67        # Artist or artist credit.
68        if config['artist_credit']:
69            item.artist = (track_info.artist_credit or
70                           track_info.artist or
71                           album_info.artist_credit or
72                           album_info.artist)
73            item.albumartist = (album_info.artist_credit or
74                                album_info.artist)
75        else:
76            item.artist = (track_info.artist or album_info.artist)
77            item.albumartist = album_info.artist
78
79        # Album.
80        item.album = album_info.album
81
82        # Artist sort and credit names.
83        item.artist_sort = track_info.artist_sort or album_info.artist_sort
84        item.artist_credit = (track_info.artist_credit or
85                              album_info.artist_credit)
86        item.albumartist_sort = album_info.artist_sort
87        item.albumartist_credit = album_info.artist_credit
88
89        # Release date.
90        for prefix in '', 'original_':
91            if config['original_date'] and not prefix:
92                # Ignore specific release date.
93                continue
94
95            for suffix in 'year', 'month', 'day':
96                key = prefix + suffix
97                value = getattr(album_info, key) or 0
98
99                # If we don't even have a year, apply nothing.
100                if suffix == 'year' and not value:
101                    break
102
103                # Otherwise, set the fetched value (or 0 for the month
104                # and day if not available).
105                item[key] = value
106
107                # If we're using original release date for both fields,
108                # also set item.year = info.original_year, etc.
109                if config['original_date']:
110                    item[suffix] = value
111
112        # Title.
113        item.title = track_info.title
114
115        if config['per_disc_numbering']:
116            # We want to let the track number be zero, but if the medium index
117            # is not provided we need to fall back to the overall index.
118            if track_info.medium_index is not None:
119                item.track = track_info.medium_index
120            else:
121                item.track = track_info.index
122            item.tracktotal = track_info.medium_total or len(album_info.tracks)
123        else:
124            item.track = track_info.index
125            item.tracktotal = len(album_info.tracks)
126
127        # Disc and disc count.
128        item.disc = track_info.medium
129        item.disctotal = album_info.mediums
130
131        # MusicBrainz IDs.
132        item.mb_trackid = track_info.track_id
133        item.mb_releasetrackid = track_info.release_track_id
134        item.mb_albumid = album_info.album_id
135        if track_info.artist_id:
136            item.mb_artistid = track_info.artist_id
137        else:
138            item.mb_artistid = album_info.artist_id
139        item.mb_albumartistid = album_info.artist_id
140        item.mb_releasegroupid = album_info.releasegroup_id
141
142        # Compilation flag.
143        item.comp = album_info.va
144
145        # Track alt.
146        item.track_alt = track_info.track_alt
147
148        # Miscellaneous/nullable metadata.
149        misc_fields = {
150            'album': (
151                'albumtype',
152                'label',
153                'asin',
154                'catalognum',
155                'script',
156                'language',
157                'country',
158                'albumstatus',
159                'albumdisambig',
160                'releasegroupdisambig',
161                'data_source',
162            ),
163            'track': (
164                'disctitle',
165                'lyricist',
166                'media',
167                'composer',
168                'composer_sort',
169                'arranger',
170            )
171        }
172
173        # Don't overwrite fields with empty values unless the
174        # field is explicitly allowed to be overwritten
175        for field in misc_fields['album']:
176            clobber = field in config['overwrite_null']['album'].as_str_seq()
177            value = getattr(album_info, field)
178            if value is None and not clobber:
179                continue
180            item[field] = value
181
182        for field in misc_fields['track']:
183            clobber = field in config['overwrite_null']['track'].as_str_seq()
184            value = getattr(track_info, field)
185            if value is None and not clobber:
186                continue
187            item[field] = value
188