pgdl-7.77: src/Main.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
import FetchHtml
import PrsVid
import NameAlgo
import RealWorld
import Chkcfg
import Video
import Log
import GenStat
import CrtInf
import AskScene
import Data.IORef
import Data.Maybe
import Control.Applicative
import Control.Concurrent
import Control.Monad
import System.Exit
import System.Environment
import Graphics.Vty
import Graphics.Vty.Widgets.All
main :: IO ()
main = do
chkcfg
-- check if there exists a configuration file, if not, then create one
c <- newCollection
lst <- newList 3
-- the main list will display on screen
diskrd <- readVid
-- read cache in the disk, if the cache do not exists, return "downloading"
args <- getArgs
let diskV = if null args then diskrd
else dlnVid
-- if user want to search a video, then don't load cache to the screen
forM_ diskV $ \v -> addToList lst v =<< plainText (beaut v)
-- add disk videos to list
lfg <- newFocusGroup
addToFocusGroup lfg lst
statBar <- plainText waitingBar
-- the state bar show in the bottom
setNormalAttribute statBar (black `on` green)
ui <- centered =<< hFixed 80 =<< vBox lst statBar
-- ui consists of a list and a state bar
chgls <- addToCollection c ui lfg
(dlg, dfcg) <- newAskScene
dui <- centered =<< hFixed 50 (sceneWidget dlg)
chgdl <- addToCollection c dui dfcg
-- four button in ask scene's action
onScePlay dlg $ \_ -> do
Just (_, (itm, _)) <- getSelected lst
justPlay itm
onSceDown dlg $ \_ -> do
Just (_, (itm, _)) <- getSelected lst
playVid itm
onSceQuit dlg $ const exitSuccess
onSceRemv dlg $ \_ -> do
Just (_, (itm, _)) <- getSelected lst
removeVid itm
ifsfg <- newFocusGroup
-- a focus group for information page
-- this function will show the focused item's information to user
let chgInf = do
Just (_, (vid, _)) <- getSelected lst
inf <- centered =<< plainText (crtInfPg vid)
addToFocusGroup ifsfg inf
join $ addToCollection c inf ifsfg
-- the information scene
onKeyPressed ifsfg $ \_ key _ -> case key of
KLeft -> do
chgls -- return to the list
return True
KUp -> do
scrollUp lst
chgInf
return True
KDown -> do
scrollDown lst
chgInf
return True
_ -> return False
onKeyPressed lst $ \_ key _ -> case key of
KRight -> do
chgInf
return True
_ -> return False
lfg `onKeyPressed` tryExit
dfcg `onKeyPressed` tryExit
ifsfg `onKeyPressed` tryExit
-- let's download video from internet !
schedule $ do
forkIO $ do
rd <- prsHtm <$> fetchHtml
-- prsHtm :: Text -> [Video (whether video or folder)]
let vdlst = search rd args
when (length vdlst < 1) $ error "no search result found (or it's empty)."
Just (_, (oldItm, _)) <- getSelected lst
-- store the location before page refresh
clearList lst
forM_ vdlst $ \v -> addToList lst v =<< plainText (beaut v)
-- show new list
listFindFirst lst oldItm >>= \case
Just ind -> setSelected lst ind
Nothing -> return ()
onSelectionChange lst $ \sle -> case sle of
SelectionOn _ itm _ -> case isFld itm of
True -> setFocusAttribute lst (black `on` magenta)
-- folder's color
_ -> fex itm >>= \case
True -> setFocusAttribute lst (black `on` red)
-- if video have been download, use red color
False -> setFocusAttribute lst (black `on` cyan)
-- if video haven't been download, use cyan
_ -> return ()
onSelectionChange lst $ \sle -> case sle of
SelectionOn _ itm _ -> setText statBar =<< genStat itm
-- refresh state bar after any scroll
_ -> return ()
astr <- newIORef []
-- we store ancestors list element in the astr
-- (those old list we leaved)
let push = do
-- store the state into astr
sz <- getListSize lst
Just (loc, _) <- getSelected lst
lem <- catMaybes <$> forM [0..sz-1] (getListItem lst)
modifyIORef astr ((lem, loc):)
let pop = do
-- pop a state from astr and give it to lst
ast <- readIORef astr
case ast of
[] -> return ()
((itms, loc):_) -> do
clearList lst
forM_ itms $ \(v, w) -> addToList lst v w
setSelected lst loc
modifyIORef astr tail
let openFld lnk = do
ctnt <- (map (attcLink lnk) . prsHtm) <$> fetchFld lnk
-- attach folder link to the videos in the folder
when (null ctnt) $ error "there is no video in the folder!"
push
clearList lst
forM_ ctnt $ \v -> addToList lst v =<< plainText (beaut v)
return ()
onKeyPressed lst $ \_ key _ -> case key of
KEnter -> do
-- User can choose a folder or a video !
Just (_, (itm, _)) <- getSelected lst
case itm of
Folder _ lnk _ -> openFld lnk
v -> fex v >>= \case
True -> chgdl
False -> playVid itm
return True
KLeft -> do
-- return to the old list
pop
return True
KChar 's' -> do
push
Just (_, (itm, _)) <- getSelected lst
size <- getListSize lst
let itemIdxs = reverse [0..size-1]
isLik <- forM itemIdxs $ \idx -> do
Just (now, _) <- getListItem lst idx
return $ isAlike itm now
forM_ (zip itemIdxs isLik) $ \(idx, lik) -> unless lik $ do
removeFromList lst idx
return ()
return True
_ -> return False
when (null args) $ void . forkIO . writeVid $ vdlst
-- only write cache when user didn't search video
return ()
return ()
runUi c $ defaultContext { normalAttr = white `on` black
, focusAttr = black `on` blue
}
where tryExit _ key _ = case key of
KChar 'q' -> exitSuccess
_ -> return False
fex itm
| isVid itm = downloaded $ vidName itm
| otherwise = return False