Ejemplo n.º 1
0
    def __init__(self, parent=None, title="TagEditor"):
        """Initializes GUI elements and the model."""
        wx.Frame.__init__(self, parent, title=title, style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
        icon = wx.Icon("tag.png", wx.BITMAP_TYPE_PNG)
        self.SetIcon(icon)
        self.tagger = Tagger()
        self.tags = {}
        self.dirname = ''
        self.cur_id = 0
        self.selected_tags = self.default_tags

        # Basically, the Program consists of three main regions:
        # | Menu     |
        # ------------ 
        # | Editor   |
        # ------------ 
        # | Filelist |
        self.menubar()
        self.mainpane = wx.Panel(self)
        self.mainsizer = wx.BoxSizer(wx.HORIZONTAL)
        self.editpane = wx.GridBagSizer(hgap=28, vgap=5)
        self.fill_editor(True)
        self.listpane = self.filelist(self.mainpane)

        self.mainsizer.Add(self.editpane, 1, wx.EXPAND|wx.ALL, 10)
        self.mainsizer.Add(self.listpane, 1, wx.EXPAND|wx.ALL, 0)

        self.Show(True)
        self.Center()

        self.refresh("initial")
Ejemplo n.º 2
0
 def setUpClass(self):
     self.tagger = Tagger()
     self.testdir = "../Testset/"
     self.testdir_deep = "../Woods of Ypres/"
     # Copy a fresh instance of the testfiles to the test directory
     shutil.rmtree(self.testdir)
     shutil.copytree("../TestsetClean/", self.testdir)
     self.testfile = self.testdir + "Woods of Ypres (Woods III_ Deepest Roots and Darkest Blues) - 01 - The Northern Cold.mp3"
Ejemplo n.º 3
0
class TaggingTests(unittest.TestCase):
    """Some unit testing for the model"""
    
    @classmethod
    def setUpClass(self):
        self.tagger = Tagger()
        self.testdir = "../Testset/"
        self.testdir_deep = "../Woods of Ypres/"
        # Copy a fresh instance of the testfiles to the test directory
        shutil.rmtree(self.testdir)
        shutil.copytree("../TestsetClean/", self.testdir)
        self.testfile = self.testdir + "Woods of Ypres (Woods III_ Deepest Roots and Darkest Blues) - 01 - The Northern Cold.mp3"

    def test_open_file(self):
        self.tagger.add_file(self.testfile)
        self.assertEqual(len(self.tagger.files), 1)
        self.tagger.add_file(self.testfile)
        self.assertEqual(len(self.tagger.files), 1)

    def test_open_invalid_file(self):
        self.tagger.add_file("test.py")
        self.assertEqual(len(self.tagger.files), 0)

    def test_read(self):
        self.tagger.add_file(self.testfile)
        self.assertEqual(self.tagger.read_single(0, "artist"), [u"Woods of Ypres"])

    def test_write_single(self):
        self.tagger.add_file(self.testfile)
        self.assertEqual(self.tagger.read_single(0, "artist"), [u"Woods of Ypres"])
        self.tagger.write_single(0, "artist", "Ypres of Woods")
        self.tagger.save_all()
        self.tagger.add_file(self.testfile)
        self.assertEqual(self.tagger.read_single(0, "artist"), [u"Ypres of Woods"])
        self.tagger.write_single(0, "artist", "Woods of Ypres")
        self.tagger.save_all()
        self.tagger.add_file(self.testfile)
        self.assertEqual(self.tagger.read_single(0, "artist"), [u"Woods of Ypres"])

    def test_open_dir(self):
        self.tagger.add_dir(self.testdir) 
        self.assertEqual(len(self.tagger.files), 15)

    def test_read_all(self):
        self.tagger.add_dir(self.testdir)
        for i in range(0, len(self.tagger.files)): 
            self.assertEqual(self.tagger.read_single(i, "artist"), [u"Woods of Ypres"])

    def test_read_all_deep(self):
        self.tagger.add_dir(self.testdir_deep)
        for i in range(0, len(self.tagger.files)): 
            self.assertEqual(self.tagger.read_single(i, "artist"), [u"Woods of Ypres"])

    def test_write_all(self):
        self.tagger.add_dir(self.testdir)
        self.tagger.write_all("artist", "Woods of Ypresss")
        for i in range(0, len(self.tagger.files)): 
            self.assertEqual(self.tagger.read_single(i, "artist"), [u"Woods of Ypresss"])

    def test_write_image(self):
        self.tagger.add_file(self.testfile)
        self.tagger.write_single(0, "image", path="woods.jpg", name="test")
        images = self.tagger.read_single(0, "image")
        self.assertIsNotNone(images["test"])

    def test_get_type(self):
        self.tagger.add_file(self.testfile)
        type = self.tagger.get_type(0)
        type2 = self.tagger.read_single(0, "type")
        self.assertEqual(type, "mp3")
        # The .read()-version is wrapped in a list for consistency
        self.assertEqual(type2, ["mp3"]) 

    def test_swap(self):
        self.tagger.add_dir(self.testdir)
        file0 = self.tagger.files[0]
        file1 = self.tagger.files[1]
        self.tagger.swap(0, 1)
        self.assertEqual(file0, self.tagger.files[1])
        self.assertEqual(file1, self.tagger.files[0])

    def test_utf8(self):
        self.tagger.add_file(self.testfile)
        special = unicode("öäüß–…·§%&@€", "utf-8")
        self.tagger.write_single(0, "title", special)
        self.assertEqual(special, self.tagger.read_single(0, "title")[0])
        self.tagger.save_single(0)
        self.tagger.add_file(self.testfile)
        self.assertEqual(special, self.tagger.read_single(0, "title")[0])
Ejemplo n.º 4
0
class TagEditor(wx.Frame):
    """The core of the graphical tagger frontend."""

    # Typical tags to be enabled by default
    default_tags = ["artist", "title", "album", "genre", "tracknumber", "image"]

    def __init__(self, parent=None, title="TagEditor"):
        """Initializes GUI elements and the model."""
        wx.Frame.__init__(self, parent, title=title, style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
        icon = wx.Icon("tag.png", wx.BITMAP_TYPE_PNG)
        self.SetIcon(icon)
        self.tagger = Tagger()
        self.tags = {}
        self.dirname = ''
        self.cur_id = 0
        self.selected_tags = self.default_tags

        # Basically, the Program consists of three main regions:
        # | Menu     |
        # ------------ 
        # | Editor   |
        # ------------ 
        # | Filelist |
        self.menubar()
        self.mainpane = wx.Panel(self)
        self.mainsizer = wx.BoxSizer(wx.HORIZONTAL)
        self.editpane = wx.GridBagSizer(hgap=28, vgap=5)
        self.fill_editor(True)
        self.listpane = self.filelist(self.mainpane)

        self.mainsizer.Add(self.editpane, 1, wx.EXPAND|wx.ALL, 10)
        self.mainsizer.Add(self.listpane, 1, wx.EXPAND|wx.ALL, 0)

        self.Show(True)
        self.Center()

        self.refresh("initial")

    def menubar(self):
        """Hooks a simple menu bar into the frame."""
        menubar = wx.MenuBar()
        filemenu = wx.Menu()

        menubar.action_open = filemenu.Append(wx.ID_ANY, "Tag F&iles", "Open Files for Tagging")
        menubar.action_open_dir = filemenu.Append(wx.ID_ANY, "Tag F&olders", "Open Files for Tagging")
        menubar.action_save = filemenu.Append(wx.ID_ANY, "&Save", "Write Tags to Files")
        menubar.action_exit =filemenu.Append(wx.ID_ANY, "&Quit", "Exit PYD3Tagger")

        self.Bind(wx.EVT_MENU, self.open, menubar.action_open)
        self.Bind(wx.EVT_MENU, self.open_dir, menubar.action_open_dir)
        self.Bind(wx.EVT_MENU, self.save, menubar.action_save)
        self.Bind(wx.EVT_MENU, self.exit, menubar.action_exit)

        menubar.Append(filemenu, "&File")
        self.menubar = menubar
        self.SetMenuBar(menubar)
 
    def fill_editor(self, initial=False):
        """Replaces the tag editor contents with updated values or a different set of widgets."""
        self.editpane.Clear(True) # We have to clear old elements before adding new ones

        # We only show a subset of the ID3/Ogg/Flac-Metadata to keep things simple.
        # TODO: Add Setting for available tag types
        row = 0
        for tag_type in self.selected_tags:
            if tag_type != "image" or not self.tagger.get_ids() or self.tagger.get_type(self.cur_id) == "mp3":
                tag = TagFactory.create_tag(self, tag_type, self.tagger, self.cur_id) 
                widgets = tag.get_widgets(self.mainpane)
                row = tag.place_widgets(widgets, self.editpane, row)
                self.tags[tag_type] = tag
                if self.tagger.get_ids():
                    tag.fill()

        # When we first initialize the Widgets there is no file to edit, so widgets are greyed out.
        children = self.GetChildren()
        for child in children:
            child.Enable(not initial)
            self.menubar.action_save.Enable(not initial)

    def filelist(self, main, refresh=False):
        # TODO: Refactor into wx.ListCtrl subclass together with swapup, -down, etc.
        # TODO: Drag and Drop Support for reordering
        """Adds a tabular list structure for the file selection."""
        up = wx.Button(main, label="Up")
        up.Bind(wx.EVT_BUTTON, self.swapup)
        down = wx.Button(main, label="Down")
        down.Bind(wx.EVT_BUTTON, self.swapdown)
        listsizer = wx.BoxSizer(wx.VERTICAL)
        listbuttons = wx.BoxSizer(wx.HORIZONTAL)
        listbuttons.Add(up, wx.ALL, 5)
        listbuttons.Add(down, 0, wx.ALIGN_RIGHT|wx.ALL, 5)

        listsizer.Add(listbuttons, 0, wx.ALIGN_RIGHT)
        filelist = wx.ListCtrl(main, style=wx.LC_REPORT, size=(630, 200))
        for (i, title) in enumerate(["#", "Artist", "Album", "Title", "Path"]):
            filelist.InsertColumn(i, title)
        self.filelist = filelist
        listsizer.Add(filelist, 1, wx.EXPAND|wx.ALL, 0)

        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.select_file, self.filelist)
        return listsizer

    def swapup(self, event):
        """Swap list items upwards."""
        items = self.get_selection()
        for item in items:
            if item-1 >= 0:
                self.tagger.swap(item, item-1)
        self.refresh("list")

    def swapdown(self, event):
        """Bubble list items down."""
        items = self.get_selection()[::-1]
        for item in items:
            if item+1 < len(self.tagger.get_ids()):
                self.tagger.swap(item, item+1)
        self.refresh("list")

    def fill_filelist(self):
        """Change or exchange the entries in the file list."""
        for file_id in self.tagger.get_ids():
            tracknumber = self.tagger.read_single(file_id, "tracknumber")[0]
            if self.filelist.GetItemCount() > file_id:
                self.filelist.SetStringItem(file_id, 0, tracknumber)
            else:
                self.filelist.InsertStringItem(file_id, tracknumber)
            for (i, tag) in enumerate(["artist", "album", "title", "path"]):
                self.filelist.SetStringItem(file_id, i+1, self.tagger.read_single(file_id, tag)[0])
        for i in range(0, self.filelist.GetColumnCount()):
            self.filelist.SetColumnWidth(i, wx.LIST_AUTOSIZE)

    def get_selection(self):
        """Retrieve the list items that are currently selected."""
        selection = []
        selected = self.filelist.GetFirstSelected(self)
        while selected != -1:
            selection.append(selected)
            selected = self.filelist.GetNextSelected(selected)
        return selection

    def select_file(self, event):
        """Change the currently edited file to the selected one."""
        self.cur_id = event.GetIndex()   
        self.refresh("editor")

    def refresh(self, type):  
        """Redraw and refill parts of the application."""
        if type in ["editor", "list", "both"]:
            if type != "list":
                self.fill_editor()
            if type != "editor":
                self.fill_filelist()
            self.Refresh()
        self.mainpane.SetSizerAndFit(self.mainsizer)
        self.SetSizeHints(self.GetBestSize().width, self.GetBestSize().height) 
         
    def exit(self, event):
        """Exit ;-)"""
        self.Close(True)

    def open(self, event):
        """File-opening dialog."""
        dlg = wx.FileDialog(self, "Choose files to tag", self.dirname, "", "*.*", wx.OPEN|wx.MULTIPLE)
        if dlg.ShowModal() == wx.ID_OK:
            files = dlg.GetPaths()
            self.dirname = dlg.GetDirectory()
            self.tagger.add_files(files)
            self.refresh("both")
        dlg.Destroy()
    
    def open_dir(self, event):
        """Directory-open dialog."""
        dlg = wx.DirDialog(self, "Choose a folder to tag", self.dirname)
        if dlg.ShowModal() == wx.ID_OK:
            directory = dlg.GetPath()
            self.dirname = directory
            self.tagger.add_dir(directory)
            self.refresh("both")
        dlg.Destroy()

    def save(self, event):
        """Save the changed to file."""
        self.tagger.save_all()