aboutsummaryrefslogtreecommitdiff
path: root/vidslice.py
blob: 30c2c73f91e30ac71145ba84eeb334428af3938e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import subprocess
import sys

import wx
import wx.adv

from options import OptionsPanel
from output import OutputPanel
from sources import SourcesPanel, update_ytdl


def has_ffmpeg():
    try:
        subprocess.run(["ffmpeg", "-version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        return True
    except FileNotFoundError:
        return False


class VidsliceFrame(wx.Frame):
    """
    A Frame that contains vidslice logic
    """

    def __init__(self, *args, **kw):
        # ensure the parent's __init__ is called
        super(VidsliceFrame, self).__init__(*args, **kw)

        root_sizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(root_sizer)
        main = wx.Panel(self)
        root_sizer.Add(main, proportion=1, flag=wx.EXPAND, border=5)
        main_sizer = wx.GridBagSizer(5, 5)
        main.SetSizer(main_sizer)

        # set up sources panel
        self.sources_panel = SourcesPanel(main)
        main_sizer.Add(self.sources_panel, wx.GBPosition(0, 0), wx.GBSpan(1, 2), flag=wx.EXPAND)

        # set up options panel
        self.options_panel = OptionsPanel(main)
        main_sizer.Add(self.options_panel, wx.GBPosition(1, 0), flag=wx.EXPAND)
        main_sizer.AddGrowableRow(1, proportion=1)
        self.sources_panel.on_update(self.options_panel.update)

        # set up output panel
        self.output_panel = OutputPanel(main, get_ffmpeg_args=self.options_panel.ffmpeg_opts)
        main_sizer.Add(self.output_panel, wx.GBPosition(1, 1), flag=wx.EXPAND)
        main_sizer.AddGrowableCol(1, proportion=1)
        self.sources_panel.on_update(lambda data: self.output_panel.set_input_path(self.sources_panel.get_file(), data))

        # create a menu bar
        self.make_menu_bar()

        size = root_sizer.GetMinSize()
        self.SetMinClientSize(size)

        if len(sys.argv) > 1:
            self.sources_panel.file_text.SetValue(sys.argv[1])

    def make_menu_bar(self):
        """
        A menu bar is composed of menus, which are composed of menu items.
        This method builds a set of menus and binds handlers to be called
        when the menu item is selected.
        """

        # Make a file menu with Hello and Exit items
        file_menu = wx.Menu()
        # The "\t..." syntax defines an accelerator key that also triggers
        # the same event
        update_item = file_menu.Append(-1, "Update youtube-dl")
        file_menu.AppendSeparator()
        # When using a stock ID we don't need to specify the menu item's
        # label
        exit_item = file_menu.Append(wx.ID_EXIT)

        # Now a help menu for the about item
        help_menu = wx.Menu()
        about_item = help_menu.Append(wx.ID_ABOUT)

        # Make the menu bar and add the two menus to it. The '&' defines
        # that the next letter is the "mnemonic" for the menu item. On the
        # platforms that support it those letters are underlined and can be
        # triggered from the keyboard.
        menu_bar = wx.MenuBar()
        menu_bar.Append(file_menu, "&File")
        menu_bar.Append(help_menu, "&Help")

        # Give the menu bar to the frame
        self.SetMenuBar(menu_bar)

        # Finally, associate a handler function with the EVT_MENU event for
        # each of the menu items. That means that when that menu item is
        # activated then the associated handler function will be called.
        self.Bind(wx.EVT_MENU, self.on_update, update_item)
        self.Bind(wx.EVT_MENU, self.on_exit, exit_item)
        self.Bind(wx.EVT_MENU, self.on_about, about_item)

    def on_exit(self, event):
        """Close the frame, terminating the application."""
        self.Close(True)

    def on_update(self, event):
        import threading
        threading.Thread(target=update_ytdl, args=(self,)).start()

    def on_about(self, event):
        """Display an About Dialog"""
        info = wx.adv.AboutDialogInfo()
        info.SetName("vidslice")
        info.SetVersion("1.0")
        info.SetDescription("video manipulator wrapping youtube-dl and ffmpeg")
        info.SetWebSite("https://github.com/boringcactus/vidslice")

        wx.adv.AboutBox(info)


if __name__ == '__main__':
    # When this module is run (not imported) then create the app, the
    # frame, show it, and start the event loop.
    app = wx.App()
    if not has_ffmpeg():
        answer = wx.MessageBox("Could not find ffmpeg. Open vidslice README?", "Error", wx.YES_NO, None)
        if answer == wx.YES:
            import webbrowser

            webbrowser.open("https://github.com/boringcactus/vidslice/blob/master/README.md")
    else:
        frm = VidsliceFrame(None, title='vidslice')
        app.SetTopWindow(frm)
        frm.Show()
    app.MainLoop()