1# Copyright (C) 2011 Dustin Spicuzza
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, or (at your option)
6# any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program; if not, write to the Free Software
15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16#
17#
18# The developers of the Exaile media player hereby grant permission
19# for non-GPL compatible GStreamer and Exaile plugins to be used and
20# distributed together with GStreamer and Exaile. This permission is
21# above and beyond the permissions granted by the GPL license by which
22# Exaile is covered. If you modify this code, you may extend this
23# exception to your version of the code, but you are not obligated to
24# do so. If you do not wish to do so, delete this exception statement
25# from your version.
26
27#
28# Grouping field utility functions
29#
30
31
32from gi.repository import Gtk
33from gi.repository import GObject
34
35import re
36
37from xl import playlist, settings
38
39from xl.nls import gettext as _
40from xl.trax import search
41
42from xlgui import main
43from xlgui.widgets import dialogs
44
45from . import gt_widgets
46
47
48group_categories_option = 'plugin/grouptagger/group_categories'
49migrated_option = 'plugin/grouptagger/0.2_migration'
50tagname_option = 'plugin/grouptagger/tagname'
51
52
53def migrate_settings():
54    '''Automatically migrate group tagger 0.1 settings to 0.2'''
55
56    if settings.get_option(migrated_option, False):
57
58        default_groups = settings.get_option('plugin/grouptagger/default_groups', None)
59        if default_groups is not None:
60            group_categories = {_('Uncategorized'): [True, default_groups]}
61            set_group_categories(group_categories)
62            # settings.remove_option( 'plugin/grouptagger/default_groups' )
63
64        settings.set_option(migrated_option, True)
65
66
67def get_tagname():
68    return settings.get_option(tagname_option, 'grouping')
69
70
71def get_track_groups(track):
72    """
73    Returns a set() of groups present in this track
74    """
75    return _get_track_groups(track, get_tagname())
76
77
78def _get_track_groups(track, tagname):
79    grouping = track.get_tag_raw(tagname, True)
80
81    if grouping is not None:
82        return {group.replace('_', ' ') for group in grouping.split()}
83
84    return set()
85
86
87def set_track_groups(track, groups):
88    """
89    Given an array of groups, sets them on a track
90
91    Returns true if successful, false if there was an error
92    """
93
94    grouping = ' '.join(sorted('_'.join(group.split()) for group in groups))
95    track.set_tag_raw(get_tagname(), grouping)
96
97    if not track.write_tags():
98        dialogs.error(
99            None,
100            "Error writing tags to %s"
101            % GObject.markup_escape_text(track.get_loc_for_io()),
102        )
103        return False
104
105    return True
106
107
108def get_group_categories():
109    """
110    Returns a dictionary that contains a mapping of default groups
111    to categories.
112
113    Structure: { category: [expanded, [group, ... ]], ... }
114    """
115
116    return settings.get_option(group_categories_option, dict())
117
118
119def get_groups_from_categories():
120
121    groups = set()
122    categories = get_group_categories()
123    for category, (expanded, cgroups) in categories.items():
124        for group in cgroups:
125            groups.add(group)
126    return groups
127
128
129def set_group_categories(group_categories):
130    """
131    Set the mapping of default groups to categories
132    """
133    settings.set_option(group_categories_option, group_categories)
134
135
136def get_all_collection_groups(collection):
137    """
138    For a given collection of tracks, return all groups
139    used within that collection
140    """
141    groups = set()
142    for track in collection:
143        groups |= get_track_groups(track)
144
145    return groups
146
147
148def _create_search_playlist(name, search_string, exaile):
149    '''Create a playlist based on a search string'''
150    tracks = [
151        x.track
152        for x in search.search_tracks_from_string(exaile.collection, search_string)
153    ]
154
155    # create the playlist
156    pl = playlist.Playlist(name, tracks)
157    main.get_playlist_notebook().create_tab_from_playlist(pl)
158
159
160def create_all_search_playlist(groups, exaile):
161    '''Create a playlist of tracks that have all groups selected'''
162
163    tagname = get_tagname()
164
165    name = '%s: %s' % (tagname.title(), ' and '.join(groups))
166    search_string = ' '.join(
167        [
168            '%s~"\\b%s\\b"' % (tagname, re.escape(group.replace(' ', '_')))
169            for group in groups
170        ]
171    )
172
173    _create_search_playlist(name, search_string, exaile)
174
175
176def create_custom_search_playlist(groups, exaile):
177    '''Create a playlist based on groups, and user input in a shiny dialog'''
178
179    dialog = gt_widgets.GroupTaggerQueryDialog(groups)
180    if dialog.run() == Gtk.ResponseType.OK:
181        name, search_string = dialog.get_search_params()
182        _create_search_playlist(name, search_string, exaile)
183
184    dialog.destroy()
185