packages feed

hmp3-ng-2.18.0: app/Main.hs

-- Copyright (c) Don Stewart 2004-2008.
-- Copyright (c) Tuomo Valkonen 2004.
-- Copyright (c) 2019-2026 Galen Huntington
-- SPDX-License-Identifier: GPL-2.0-or-later

module Main where

import Base

import Core     (start, shutdown, Options(..))
import qualified Config
import Tree     (buildTree, isEmpty)

import System.IO            (hPrint, stderr)
import System.Posix.Signals (installHandler, sigTERM, sigPIPE, sigINT, sigHUP
                            ,sigALRM, sigABRT, Handler(Ignore, Default, Catch))

import qualified Data.ByteString.UTF8 as UTF8

import Options.Applicative

-- ---------------------------------------------------------------------
-- | Set up the signal handlers

initSignals :: IO ()
initSignals = do
    -- ignore
    for_ [sigPIPE, sigALRM] \sig ->
        installHandler sig Ignore Nothing
    -- and exit if we get the following
    for_ [sigINT, sigHUP, sigABRT, sigTERM] \sig ->
        installHandler sig (Catch exitHandler) Nothing

exitHandler :: IO ()
exitHandler = do
    releaseSignals  -- in case shutdown itself gets stuck
    catch @SomeException (shutdown Nothing) (hPrint stderr)
    exitWith $ ExitFailure 1

releaseSignals :: IO ()
releaseSignals =
    for_ [sigINT, sigPIPE, sigHUP, sigABRT, sigTERM] \sig ->
        installHandler sig Default Nothing

------------------------------------------------------------------------
-- | Command-line parsing.

-- | The options together with the file/directory arguments.
invocation :: Parser (Options, [ByteString])
invocation = (,) <$> opts <*> files
  where
    opts = Options
        <$> switch
            (long "paused" <> short 'P' <> help "Start in a paused state")
        <*> optional (strOption -- temporarily internal since feature needs work
            (long "config" <> short 'c' <> metavar "FILE" <> internal
                <> help "Read this config file instead of the XDG default"))
    files = some $ argument (UTF8.fromString <$> str) (metavar "FILE|DIR...")

parserInfo :: ParserInfo (Options, [ByteString])
parserInfo = info (invocation <**> versionOpt <**> helper) $
       fullDesc
    <> header Config.versinfo
    <> progDesc "Play mp3 files in a curses interface."
  where
    versionOpt = infoOption Config.versinfo
        (hidden <> long "version" <> short 'V' <> help "Show version information")

------------------------------------------------------------------------

main :: IO ()
main = do
    (opts, args) <- customExecParser (prefs showHelpOnEmpty) parserInfo
    initSignals
    tree <- buildTree args
    if isEmpty tree
        then putStrLn "Error: No music files found." *> exitFailure
        else start opts tree -- never returns