monatone-0.1.0.0: app/Main.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE BangPatterns #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Main (main) where
import Data.Aeson (encode, ToJSON, object, (.=))
import Data.Aeson.Types (ToJSON(..))
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy.Char8 as L8
import qualified Data.Text as T
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import Data.Word (Word8)
import System.Environment (getArgs)
import System.Exit (exitFailure)
import System.OsPath
import Monatone.Common (parseMetadata)
import Monatone.Metadata
-- Make Metadata instance for ToJSON
instance ToJSON Metadata where
toJSON metadata = object
[ "format" .= format metadata
, "title" .= title metadata
, "artist" .= artist metadata
, "album" .= album metadata
, "albumArtist" .= albumArtist metadata
, "trackNumber" .= trackNumber metadata
, "totalTracks" .= totalTracks metadata
, "discNumber" .= discNumber metadata
, "totalDiscs" .= totalDiscs metadata
, "date" .= date metadata
, "year" .= year metadata
, "genre" .= genre metadata
, "publisher" .= publisher metadata
, "comment" .= comment metadata
, "releaseCountry" .= releaseCountry metadata
, "recordLabel" .= recordLabel metadata
, "catalogNumber" .= catalogNumber metadata
, "barcode" .= barcode metadata
, "releaseStatus" .= releaseStatus metadata
, "releaseType" .= releaseType metadata
, "albumArtInfo" .= albumArtInfo metadata
, "audioProperties" .= audioProperties metadata
, "musicBrainzIds" .= musicBrainzIds metadata
, "acoustidFingerprint" .= acoustidFingerprint metadata
, "acoustidId" .= acoustidId metadata
, "rawTags" .= rawTags metadata
]
instance ToJSON AudioProperties where
toJSON props = object
[ "duration" .= duration props
, "bitrate" .= bitrate props
, "sampleRate" .= sampleRate props
, "channels" .= channels props
, "bitsPerSample" .= bitsPerSample props
]
instance ToJSON MusicBrainzIds where
toJSON ids = object
[ "mbRecordingId" .= mbRecordingId ids
, "mbTrackId" .= mbTrackId ids
, "mbReleaseId" .= mbReleaseId ids
, "mbArtistId" .= mbArtistId ids
, "mbAlbumArtistId" .= mbAlbumArtistId ids
, "mbReleaseGroupId" .= mbReleaseGroupId ids
, "mbWorkId" .= mbWorkId ids
, "mbDiscId" .= mbDiscId ids
]
instance ToJSON AlbumArtInfo where
toJSON art = object
[ "mimeType" .= albumArtInfoMimeType art
, "pictureType" .= albumArtInfoPictureType art
, "description" .= albumArtInfoDescription art
, "sizeBytes" .= albumArtInfoSizeBytes art
]
instance ToJSON AlbumArt where
toJSON art = object
[ "mimeType" .= albumArtMimeType art
, "pictureType" .= albumArtPictureType art
, "description" .= albumArtDescription art
, "dataSize" .= BS.length (albumArtData art)
-- Don't include base64 data in terminal output, just size
]
main :: IO ()
main = do
args <- getArgs
case args of
[filePathStr] -> do
putStrLn $ "Parsing file: " ++ filePathStr
-- Convert string to OsPath
filePath <- encodeFS filePathStr
result <- parseMetadata filePath
case result of
Left err -> do
putStrLn $ "Error: " ++ show err
exitFailure
Right metadata -> do
putStrLn "=== PARSED METADATA ==="
L8.putStrLn $ encode metadata
putStrLn ""
putStrLn "=== HUMAN READABLE ==="
printMetadata metadata
_ -> do
putStrLn "Usage: monatone <audio-file>"
exitFailure
-- | Format track or disc info with total if available
formatTrackInfo :: Maybe Int -> Maybe Int -> Text
formatTrackInfo Nothing _ = "null"
formatTrackInfo (Just num) Nothing = T.pack $ show num
formatTrackInfo (Just num) (Just total) = T.pack $ show num ++ "/" ++ show total
printMetadata :: Metadata -> IO ()
printMetadata metadata = do
putStrLn $ T.unpack $ "Format: " <> T.pack (show (format metadata))
putStrLn $ T.unpack $ "Title: " <> fromMaybe "null" (title metadata)
putStrLn $ T.unpack $ "Artist: " <> fromMaybe "null" (artist metadata)
putStrLn $ T.unpack $ "Album: " <> fromMaybe "null" (album metadata)
putStrLn $ T.unpack $ "Album Artist: " <> fromMaybe "null" (albumArtist metadata)
putStrLn $ T.unpack $ "Track Number: " <> formatTrackInfo (trackNumber metadata) (totalTracks metadata)
putStrLn $ T.unpack $ "Disc Number: " <> formatTrackInfo (discNumber metadata) (totalDiscs metadata)
putStrLn $ T.unpack $ "Date: " <> fromMaybe "null" (date metadata)
putStrLn $ T.unpack $ "Year: " <> maybe "null" (T.pack . show) (year metadata)
putStrLn $ T.unpack $ "Genre: " <> fromMaybe "null" (genre metadata)
putStrLn $ T.unpack $ "Publisher: " <> fromMaybe "null" (publisher metadata)
putStrLn $ T.unpack $ "Comment: " <> fromMaybe "null" (comment metadata)
putStrLn $ T.unpack $ "Release Country: " <> fromMaybe "null" (releaseCountry metadata)
putStrLn $ T.unpack $ "Record Label: " <> fromMaybe "null" (recordLabel metadata)
putStrLn $ T.unpack $ "Catalog Number: " <> fromMaybe "null" (catalogNumber metadata)
putStrLn $ T.unpack $ "Barcode: " <> fromMaybe "null" (barcode metadata)
putStrLn $ T.unpack $ "Release Status: " <> fromMaybe "null" (releaseStatus metadata)
putStrLn $ T.unpack $ "Release Type: " <> fromMaybe "null" (releaseType metadata)
putStrLn "\nAudio Properties:"
let props = audioProperties metadata
putStrLn $ T.unpack $ " Duration: " <> maybe "null" (\d -> T.pack (show d) <> "ms") (duration props)
putStrLn $ T.unpack $ " Bitrate: " <> maybe "null" (\b -> T.pack (show b) <> " kbps") (bitrate props)
putStrLn $ T.unpack $ " Sample Rate: " <> maybe "null" (\s -> T.pack (show s) <> "Hz") (sampleRate props)
putStrLn $ T.unpack $ " Channels: " <> maybe "null" (T.pack . show) (channels props)
putStrLn $ T.unpack $ " Bits Per Sample: " <> maybe "null" (T.pack . show) (bitsPerSample props)
putStrLn "\nMusicBrainz IDs:"
let mbIds = musicBrainzIds metadata
putStrLn $ T.unpack $ " Recording ID: " <> fromMaybe "null" (mbRecordingId mbIds)
putStrLn $ T.unpack $ " Track ID: " <> fromMaybe "null" (mbTrackId mbIds)
putStrLn $ T.unpack $ " Release ID: " <> fromMaybe "null" (mbReleaseId mbIds)
putStrLn $ T.unpack $ " Artist ID: " <> fromMaybe "null" (mbArtistId mbIds)
putStrLn $ T.unpack $ " Album Artist ID: " <> fromMaybe "null" (mbAlbumArtistId mbIds)
putStrLn $ T.unpack $ " Release Group ID: " <> fromMaybe "null" (mbReleaseGroupId mbIds)
putStrLn $ T.unpack $ " Work ID: " <> fromMaybe "null" (mbWorkId mbIds)
putStrLn $ T.unpack $ " Disc ID: " <> fromMaybe "null" (mbDiscId mbIds)
putStrLn "\nAcoustID:"
putStrLn $ T.unpack $ " Fingerprint: " <> fromMaybe "null" (acoustidFingerprint metadata)
putStrLn $ T.unpack $ " ID: " <> fromMaybe "null" (acoustidId metadata)
putStrLn "\nAlbum Art:"
case albumArtInfo metadata of
Nothing -> putStrLn " None"
Just artInfo -> do
putStrLn $ T.unpack $ " MIME Type: " <> albumArtInfoMimeType artInfo
putStrLn $ T.unpack $ " Picture Type: " <> T.pack (show (albumArtInfoPictureType artInfo)) <> " (" <> describePictureType (albumArtInfoPictureType artInfo) <> ")"
putStrLn $ T.unpack $ " Description: " <> if T.null (albumArtInfoDescription artInfo) then "(empty)" else albumArtInfoDescription artInfo
putStrLn $ T.unpack $ " Size: " <> T.pack (show (albumArtInfoSizeBytes artInfo)) <> " bytes"
putStrLn $ T.unpack $ "\nRaw tags count: " <> T.pack (show (length $ rawTags metadata))
describePictureType :: Word8 -> Text
describePictureType t = case t of
0 -> "Other"
1 -> "32x32 pixels 'file icon' (PNG only)"
2 -> "Other file icon"
3 -> "Cover (front)"
4 -> "Cover (back)"
5 -> "Leaflet page"
6 -> "Media (e.g. label side of CD)"
7 -> "Lead artist/lead performer/soloist"
8 -> "Artist/performer"
9 -> "Conductor"
10 -> "Band/Orchestra"
11 -> "Composer"
12 -> "Lyricist/text writer"
13 -> "Recording Location"
14 -> "During recording"
15 -> "During performance"
16 -> "Movie/video screen capture"
17 -> "A bright coloured fish"
18 -> "Illustration"
19 -> "Band/artist logotype"
20 -> "Publisher/Studio logotype"
_ -> "Unknown"