Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""LICENSE
2Copyright 2015 Hermann Krumrey <hermann@krumreyh.com>
4This file is part of toktokkie.
6toktokkie is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
11toktokkie is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
16You should have received a copy of the GNU General Public License
17along with toktokkie. If not, see <http://www.gnu.org/licenses/>.
18LICENSE"""
20import os
21import argparse
22import shutil
23from typing import List, cast
24from toktokkie.commands.Command import Command
25from toktokkie.enums import MediaType
26from toktokkie.Directory import Directory
27from toktokkie.exceptions import MissingMetadata
28from toktokkie.metadata.music.Music import Music
29from puffotter.os import listdir
32class MusicMergeCommand(Command):
33 """
34 Class that encapsulates behaviour of the music-merge command
35 """
37 @classmethod
38 def name(cls) -> str:
39 """
40 :return: The command name
41 """
42 return "music-merge"
44 @classmethod
45 def help(cls) -> str:
46 """
47 :return: The help message for the command
48 """
49 return "Combines multiple music directories into one"
51 @classmethod
52 def prepare_parser(cls, parser: argparse.ArgumentParser):
53 """
54 Prepares an argumentparser for this command
55 :param parser: The parser to prepare
56 :return: None
57 """
58 parser.add_argument("target",
59 help="Target directory. If not a toktokkie media"
60 "directory, will try to merge subfolders")
61 parser.add_argument("sources", nargs="+",
62 help="Directores containing directories to merge")
63 parser.add_argument("--keep", action="store_true",
64 help="If set, does not delete merged directories")
66 def execute(self):
67 """
68 Executes the commands
69 :return: None
70 """
71 try:
72 Directory(self.args.target)
73 targets = [self.args.target]
74 single_artist_mode = True
75 except MissingMetadata:
76 targets = [x[1] for x in listdir(self.args.target)]
77 single_artist_mode = False
79 sources = [] # type: List[str]
80 for path in self.args.sources:
81 try:
82 Directory(path)
83 sources.append(path)
84 except MissingMetadata:
85 sources += [x[1] for x in listdir(path)]
87 target_artists = Directory.load_directories(
88 targets, restrictions=[MediaType.MUSIC_ARTIST]
89 )
90 source_artists = Directory.load_directories(
91 sources, restrictions=[MediaType.MUSIC_ARTIST]
92 )
94 if single_artist_mode:
95 for source in source_artists:
96 self.merge_artists(target_artists[0], source)
98 else:
99 target_map = {x.metadata.name: x for x in target_artists}
101 for source_artist in source_artists:
102 source_metadata = cast(Music, source_artist.metadata)
104 if source_metadata.name not in target_map:
105 new_path = os.path.join(
106 self.args.target, source_metadata.name
107 )
108 shutil.copytree(source_artist.path, new_path)
109 if not self.args.keep:
110 shutil.rmtree(source_artist.path)
112 else:
113 target_artist = \
114 target_map[source_metadata.name] # type: Directory
115 self.merge_artists(target_artist, source_artist)
117 def merge_artists(
118 self,
119 target_artist: Directory,
120 source_artist: Directory
121 ):
122 """
123 Merges two artists
124 :param target_artist: The target artist
125 :param source_artist: The artist to merge into the target
126 :return: None
127 """
128 source_metadata = cast(Music, source_artist.metadata)
129 target_metadata = cast(Music, target_artist.metadata)
131 target_albums = {x.name: x for x in target_metadata.albums}
132 source_themes = {x.name: x for x in source_metadata.theme_songs}
134 for source_album in source_metadata.albums:
135 if source_album.name in target_albums:
136 self.logger.warning(
137 "Duplicate album: {}".format(source_album.name)
138 )
139 else:
140 source_path = os.path.join(
141 source_artist.path, source_album.name
142 )
143 target_path = os.path.join(
144 target_artist.path, source_album.name
145 )
146 shutil.copytree(source_path, target_path)
147 target_metadata.add_album(source_album)
149 theme_song = source_themes.get(source_album.name)
150 if theme_song is not None:
151 target_metadata.add_theme_song(theme_song)
153 target_metadata.write()
154 if not self.args.keep:
155 shutil.rmtree(source_artist.path)