1# Copyright 2004-2005 Joe Wreschnig, Michael Urman, Iñigo Serna
2#           2012,2013 Christoph Reiter
3#           2010-2017 Nick Boultbee
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9
10import sys
11import os
12
13from senf import environ, argv as sys_argv
14
15from quodlibet import _
16from quodlibet.cli import process_arguments, exit_
17from quodlibet.util.dprint import print_d, print_, print_exc
18
19
20def main(argv=None):
21    if argv is None:
22        argv = sys_argv
23
24    import quodlibet
25
26    config_file = os.path.join(quodlibet.get_user_dir(), "config")
27    quodlibet.init_cli(config_file=config_file)
28
29    try:
30        # we want basic commands not to import gtk (doubles process time)
31        assert "gi.repository.Gtk" not in sys.modules
32        sys.modules["gi.repository.Gtk"] = None
33        startup_actions, cmds_todo = process_arguments(argv)
34    finally:
35        sys.modules.pop("gi.repository.Gtk", None)
36
37    quodlibet.init()
38
39    from quodlibet import app
40    from quodlibet.qltk import add_signal_watch
41    add_signal_watch(app.quit)
42
43    import quodlibet.player
44    import quodlibet.library
45    from quodlibet import config
46    from quodlibet import browsers
47    from quodlibet import util
48
49    app.name = "Quod Libet"
50    app.description = _("Music player and music library manager")
51    app.id = "io.github.quodlibet.QuodLibet"
52    app.process_name = "quodlibet"
53    quodlibet.set_application_info(app)
54
55    library_path = os.path.join(quodlibet.get_user_dir(), "songs")
56
57    print_d("Initializing main library (%s)" % (
58            quodlibet.util.path.unexpand(library_path)))
59
60    library = quodlibet.library.init(library_path)
61    app.library = library
62
63    # this assumes that nullbe will always succeed
64    from quodlibet.player import PlayerError
65    wanted_backend = environ.get(
66        "QUODLIBET_BACKEND", config.get("player", "backend"))
67
68    try:
69        player = quodlibet.player.init_player(wanted_backend, app.librarian)
70    except PlayerError:
71        print_exc()
72        player = quodlibet.player.init_player("nullbe", app.librarian)
73
74    app.player = player
75
76    environ["PULSE_PROP_media.role"] = "music"
77    environ["PULSE_PROP_application.icon_name"] = app.icon_name
78
79    browsers.init()
80
81    from quodlibet.qltk.songlist import SongList, get_columns
82
83    headers = get_columns()
84    SongList.set_all_column_headers(headers)
85
86    for opt in config.options("header_maps"):
87        val = config.get("header_maps", opt)
88        util.tags.add(opt, val)
89
90    in_all = ("~filename ~uri ~#lastplayed ~#rating ~#playcount ~#skipcount "
91              "~#added ~#bitrate ~current ~#laststarted ~basename "
92              "~dirname").split()
93    for Kind in browsers.browsers:
94        if Kind.headers is not None:
95            Kind.headers.extend(in_all)
96        Kind.init(library)
97
98    pm = quodlibet.init_plugins("no-plugins" in startup_actions)
99
100    if hasattr(player, "init_plugins"):
101        player.init_plugins()
102
103    from quodlibet.qltk import unity
104    unity.init("io.github.quodlibet.QuodLibet.desktop", player)
105
106    from quodlibet.qltk.songsmenu import SongsMenu
107    SongsMenu.init_plugins()
108
109    from quodlibet.util.cover import CoverManager
110    app.cover_manager = CoverManager()
111    app.cover_manager.init_plugins()
112
113    from quodlibet.plugins.playlist import PLAYLIST_HANDLER
114    PLAYLIST_HANDLER.init_plugins()
115
116    from quodlibet.plugins.query import QUERY_HANDLER
117    QUERY_HANDLER.init_plugins()
118
119    from gi.repository import GLib
120
121    from quodlibet.commands import registry as cmd_registry, CommandError
122
123    def exec_commands(*args):
124        for cmd in cmds_todo:
125            try:
126                resp = cmd_registry.run(app, *cmd)
127            except CommandError:
128                pass
129            else:
130                if resp is not None:
131                    print_(resp, end="", flush=True)
132
133    from quodlibet.qltk.quodlibetwindow import QuodLibetWindow, PlayerOptions
134    # Call exec_commands after the window is restored, but make sure
135    # it's after the mainloop has started so everything is set up.
136
137    app.window = window = QuodLibetWindow(
138        library, player,
139        restore_cb=lambda:
140            GLib.idle_add(exec_commands, priority=GLib.PRIORITY_HIGH))
141
142    app.player_options = PlayerOptions(window)
143
144    from quodlibet.qltk.window import Window
145
146    from quodlibet.plugins.events import EventPluginHandler
147    from quodlibet.plugins.gui import UserInterfacePluginHandler
148    pm.register_handler(EventPluginHandler(library.librarian, player,
149                                           app.window.songlist))
150    pm.register_handler(UserInterfacePluginHandler())
151
152    from quodlibet.mmkeys import MMKeysHandler
153    from quodlibet.remote import Remote, RemoteError
154    from quodlibet.qltk.tracker import SongTracker, FSInterface
155    try:
156        from quodlibet.qltk.dbus_ import DBusHandler
157    except ImportError:
158        DBusHandler = lambda player, library: None
159
160    mmkeys_handler = MMKeysHandler(app)
161    mmkeys_handler.start()
162
163    current_path = os.path.join(quodlibet.get_user_dir(), "current")
164    fsiface = FSInterface(current_path, player)
165    remote = Remote(app, cmd_registry)
166    try:
167        remote.start()
168    except RemoteError:
169        exit_(1, True)
170
171    DBusHandler(player, library)
172    tracker = SongTracker(library.librarian, player, window.playlist)
173
174    from quodlibet import session
175    session_client = session.init(app)
176
177    quodlibet.enable_periodic_save(save_library=True)
178
179    if ("start-playing" in startup_actions or
180            (config.getboolean("player", "restore_playing", False) and
181                config.getboolean("player", "is_playing", False))):
182        player.paused = False
183
184    if "start-hidden" in startup_actions:
185        Window.prevent_inital_show(True)
186
187    # restore browser windows
188    from quodlibet.qltk.browser import LibraryBrowser
189    GLib.idle_add(LibraryBrowser.restore, library, player,
190                  priority=GLib.PRIORITY_HIGH)
191
192    def before_quit():
193        print_d("Saving active browser state")
194        try:
195            app.browser.save()
196        except NotImplementedError:
197            pass
198
199        print_d("Shutting down player device %r." % player.version_info)
200        player.destroy()
201
202    quodlibet.run(window, before_quit=before_quit)
203
204    app.player_options.destroy()
205    quodlibet.finish_first_session("quodlibet")
206    mmkeys_handler.quit()
207    remote.stop()
208    fsiface.destroy()
209
210    tracker.destroy()
211    quodlibet.library.save()
212
213    config.save()
214
215    session_client.close()
216
217    print_d("Finished shutdown.")
218