import os from parser import Parser from common import same_name_alert, get_content from tinytag import TinyTag from binascii import b2a_hex class musipy: def __init__(self): # prepare data self.data = {} self.parser = Parser() print(self.parser.source) print(self.parser.output) print(self.parser.mode) print(self.parser.attr) # run self.run() def run(self): if self.parser.mode == 'sort': self.collect() self.move_files() elif self.parser.mode == 'playlist': self.collect() self.playlist() else: pass return # sort files bases on attribute def sort(self, f, tag): # get attribute from tag # using self.attr tag = getattr(tag, self.parser.attr) if tag in self.data: self.data[tag].append(f) else: self.data[tag] = [] self.data[tag].append(f) return # move files to new destination based on attribute def move_files(self): for folder, tracks in self.data.items(): if folder is None: folder = "Undefined" if not folder: folder = "Undefined" new_folder = self.parser.output + '/' + folder if not os.path.exists(new_folder): os.makedirs(new_folder) print("Folder: {}".format(folder)) moved_files = 0 total_files = len(tracks) for track in tracks: moved_files += 1 percent = int(moved_files / total_files * 100) print("Processing ... {:3d}%".format(percent), end='\r') new_file = new_folder + '/' + os.path.basename(track) if track == new_file: # after sort, stay the same continue if os.path.exists(new_file): same_name_alert(track, new_file) else: os.rename(track, new_file) print("") return def playlist(self): print("Create playlist name {}".format(self.parser.playlistname)) pl_file = self.parser.output + '/' + self.parser.playlistname + '.m3u' mode = 'w' while os.path.exists(pl_file): rewrite = input('Playlist existed, rewrite?(y/n) ') if rewrite == 'y': break newname = input("New file name: ") pl_file = self.parser.output + '/' + newname + '.m3u' # return playlist = open(pl_file, mode) playlist.write('#EXTM3U\n') for key, musics in self.data.items(): for music in musics: tag = TinyTag.get(music) if tag.artist is None: tag.artist = '' if tag.title is None: tag.title = '' tag.duration = int(tag.duration) # write comment playlist.write('#EXTINF:{},{} - {}\n' .format(tag.duration, tag.artist, tag.title)) # change special char to hex chars = list(music) for i in range(len(music)): hex_c = ord(chars[i]) if hex_c >= ord('!') and hex_c <= ord('~'): # if in range of ascii characters continue elif hex_c == ord(' '): chars[i] = '%20' else: u = b2a_hex(chars[i].encode('utf-8')).decode('utf-8') u = list(u) for j in range(len(u)): u[j] = u[j].upper() if j % 2 != 0: continue u[j] = '%' + u[j] chars[i] = "".join(u) # print("Cannot find this character: 0x{}" # .format(hex(hex_c))) # exit(-1) music = "".join(chars) # write file direction playlist.write('file://{}\n'.format(music)) print("{} created".format(pl_file)) return # collect all files and store in self.data def collect(self): folder_queue = [self.parser.source] home_path_len = len(folder_queue[0]) while (len(folder_queue) > 0): current_folder = folder_queue[0] folder_queue = folder_queue[1:] if len(current_folder[home_path_len:]) == 0: print("[+] Scan /") else: print("[+] Scan {}".format(current_folder[home_path_len:])) files, folders = get_content(current_folder) # skip folder named '.folder' # generate full path for folder in folders: if folder[0] != '.': full_path = current_folder + '/' + folder folder_queue.append(full_path) # work with files for f in files: try: fp = current_folder + '/' + f # full path to file tag = TinyTag.get(fp) except LookupError: continue except: print("Cannot get tag from file --> Skip\n\t{}".format(fp)) continue self.sort(fp, tag) if __name__ == "__main__": muse = musipy()