#!/usr/bin/env python3 """ Fileorganizer ----------------Authors---------------- Lachlan de Waard Wolter Hellmund ----------------Licence---------------- Creative Commons - Attribution Share Alike v3.0 """ import configparser import os import shutil import gi gi.require_version('Peas', '1.0') gi.require_version('PeasGtk', '1.0') gi.require_version('Notify', '0.7') gi.require_version('RB', '3.0') from gi.repository import GObject, Peas, PeasGtk, Gtk, Notify, Gio from gi.repository import RB import fileops import tools from configurator import FileorganizerConf PLUGIN_PATH = 'plugins/fileorganizer/' CONFIGFILE = 'fo.conf' CONFIGTEMPLATE = 'fo.conf.template' UIFILE = 'config.ui' C = "conf" class Fileorganizer(GObject.Object, Peas.Activatable, PeasGtk.Configurable): """ Main class that loads fileorganizer into Rhythmbox """ __gtype_name = 'fileorganizer' object = GObject.property(type=GObject.Object) _menu_names = ['browser-popup', 'playlist-popup'] def __init__(self, *args, **kwargs): GObject.Object.__init__(self) super(Fileorganizer, self).__init__(*args, **kwargs) self.configurator = FileorganizerConf() self.conf = configparser.RawConfigParser() self.configfile = RB.find_user_data_file(PLUGIN_PATH + CONFIGFILE) self.ui_file = RB.find_user_data_file(PLUGIN_PATH + UIFILE) self.shell = None self.rbdb = None self.action_group = None self.action = None self.source = None self.plugin_info = "fileorganizer" # Rhythmbox standard Activate method def do_activate(self): """ Activate the plugin """ print("activating Fileorganizer") shell = self.object self.shell = shell self.rbdb = shell.props.db self._check_configfile() self.menu_build(shell) # Rhythmbox standard Deactivate method def do_deactivate(self): """ Deactivate the plugin """ print("deactivating Fileorganizer") app = Gio.Application.get_default() for menu_name in Fileorganizer._menu_names: app.remove_plugin_menu_item(menu_name, 'selection-' + 'organize') self.action_group = None self.action = None # self.source.delete_thyself() self.source = None # FUNCTIONS # check if configfile is present, if not copy from template folder def _check_configfile(self): """ Copy the default config template or load existing config file """ if not os.path.isfile(self.configfile): template = RB.find_user_data_file(PLUGIN_PATH + CONFIGTEMPLATE) folder = os.path.split(self.configfile)[0] if not os.path.exists(folder): os.makedirs(folder) shutil.copyfile(template, self.configfile) # Build menu option def menu_build(self, shell): """ Add 'Organize Selection' to the Rhythmbox righ-click menu """ app = Gio.Application.get_default() # create action action = Gio.SimpleAction(name="organize-selection") action.connect("activate", self.organize_selection) app.add_action(action) # create menu item item = Gio.MenuItem() item.set_label("Organize Selection") item.set_detailed_action("app.organize-selection") # add plugin menu item # app.add_plugin_menu_item('browser-popup', "Organize Selection", item) for menu_name in Fileorganizer._menu_names: app.add_plugin_menu_item(menu_name, "Organize Selection", item) app.add_action(action) # Create the Configure window in the rhythmbox plugins menu def do_create_configure_widget(self): """ Load the glade UI for the config window """ build = Gtk.Builder() build.add_from_file(self.ui_file) self._check_configfile() self.conf.read(self.configfile) window = build.get_object("fileorganizer") build.get_object("log_path").set_text(self.conf.get(C, "log_path")) if self.conf.get(C, "log_enabled") == "True": build.get_object("logbutton").set_active(True) if self.conf.get(C, "cleanup_enabled") == "True": build.get_object("cleanupbutton").set_active(True) if self.conf.get(C, "cleanup_empty_folders") == "True": build.get_object("removebutton").set_active(True) if self.conf.get(C, "preview_mode") == "True": build.get_object("previewbutton").set_active(True) if self.conf.get(C, "strip_ntfs") == "True": build.get_object("ntfsbutton").set_active(True) build.get_object("logbutton").connect('clicked', lambda x: self.save_config(build)) build.get_object("log_path").connect('changed', lambda x: self.save_config(build)) build.get_object("cleanupbutton").connect('clicked', lambda x: self.save_config(build)) build.get_object("removebutton").connect('clicked', lambda x: self.save_config(build)) build.get_object("previewbutton").connect('clicked', lambda x: self.save_config(build)) build.get_object("ntfsbutton").connect('clicked', lambda x: self.save_config(build)) return window def save_config(self, builder): """ Save changes to the plugin config """ if builder.get_object("logbutton").get_active(): self.conf.set(C, "log_enabled", "True") else: self.conf.set(C, "log_enabled", "False") if builder.get_object("cleanupbutton").get_active(): self.conf.set(C, "cleanup_enabled", "True") else: self.conf.set(C, "cleanup_enabled", "False") if builder.get_object("removebutton").get_active(): self.conf.set(C, "cleanup_empty_folders", "True") else: self.conf.set(C, "cleanup_empty_folders", "False") if builder.get_object("previewbutton").get_active(): self.conf.set(C, "preview_mode", "True") else: self.conf.set(C, "preview_mode", "False") if builder.get_object("ntfsbutton").get_active(): self.conf.set(C, "strip_ntfs", "True") else: self.conf.set(C, "strip_ntfs", "False") self.conf.set(C, "log_path", builder.get_object("log_path").get_text()) datafile = open(self.configfile, "w") self.conf.write(datafile) datafile.close() # Organize selection def organize_selection(self, action, shell): """ get your current selection and run process_selection """ page = self.shell.props.selected_page if not hasattr(page, "get_entry_view"): return selected = page.get_entry_view() selection = selected.get_selected_entries() self.process_selection(selection) # Process selection: Run in Preview Mode or Normal Mode def process_selection(self, filelist): """ using your selection, run the preview or process from fileops """ self.conf.read(self.configfile) strip_ntfs = self.conf.get(C, "strip_ntfs") == "True" # Run in Preview Modelogops if self.conf.get(C, "preview_mode") == "True": if filelist: prelist = os.getenv('HOME') + '/.fileorganizer-preview.log' datafile = open(prelist, "w") datafile.close() damlist = os.getenv('HOME') + '/.fileorganizer-damaged.log' datafile = open(damlist, "w") datafile.close() for item in filelist: item = fileops.MusicFile(self, item, strip_ntfs=strip_ntfs) item.preview() Notify.init('Fileorganizer') title = 'Fileorganizer' note = 'Preview Has Completed' notification = Notify.Notification.new(title, note, None) Notify.Notification.show(notification) # Show Results of preview tools.results(prelist, damlist) else: # Run Normally self.organize(filelist, strip_ntfs) Notify.init('Fileorganizer') title = 'Fileorganizer' note = 'Your selection is organised' notification = Notify.Notification.new(title, note, None) Notify.Notification.show(notification) return # Organize array of files def organize(self, filelist, strip_ntfs=False): """ get fileops to move media files to the correct location """ if filelist: for item in filelist: item = fileops.MusicFile(self, item, strip_ntfs=strip_ntfs) item.relocate() return class PythonSource(RB.Source): """ Register with rhythmbox """ def __init__(self): RB.Source.__init__(self) GObject.type_register_dynamic(PythonSource)