Allows you to search for videos on youtube and automatically add the audio URLs to an MPD playlist
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 

130 lines
3.9 KiB

import Control.Monad (unless)
import System.Info (os)
import System.Process (system, rawSystem)
import System.Exit (ExitCode(..))
import System.Directory (doesFileExist)
import Network.Google.OAuth2 (formUrl, exchangeCode, refreshTokens,
OAuth2Client(..), OAuth2Tokens(..))
import Network.Google (makeRequest, doRequest)
import Network.HTTP.Conduit (simpleHttp, HttpException)
import Data.Aeson
import qualified Data.ByteString.Lazy.Char8 as BL
import qualified Data.Text as T
import qualified Data.Map as M
import Control.Exception
data URL = URL { jurl :: T.Text }
deriving (Show, Eq)
data VideoID = VideoID { videoID :: T.Text }
deriving (Show, Eq)
data Thumbnail = Thumbnail { thumbnail :: URL }
deriving (Show, Eq)
data JSearchResult = JSearchResult {
jvideoID :: VideoID,
snippet :: Snippet
}
deriving (Show, Eq)
data Snippet = Snippet {
jtitle :: T.Text,
jdescription :: T.Text,
jthumbnails :: Thumbnail
}
deriving (Show, Eq)
data JItems = JItems [JSearchResult]
deriving (Show)
data SearchResult = SearchResult {
title :: T.Text,
description :: T.Text,
url :: T.Text,
thumb :: T.Text
}
deriving (Show, Eq)
instance FromJSON URL where
parseJSON (Object v) = URL <$> v .: "url"
instance FromJSON Thumbnail where
parseJSON (Object v) = Thumbnail <$> v .: "default"
instance FromJSON VideoID where
parseJSON (Object v) = VideoID <$>
v .: "videoId"
instance FromJSON Snippet where
parseJSON (Object v) = Snippet <$>
v .: "title" <*>
v .: "description" <*>
v .: "thumbnails"
instance FromJSON JSearchResult where
parseJSON (Object v) = JSearchResult <$>
(v .: "id") <*>
(v .: "snippet")
instance FromJSON JItems where
parseJSON (Object v) = JItems <$> v .: "items"
makeURL :: T.Text -> T.Text
makeURL vid = "https://youtube.com/watch?v=" `T.append` vid
getItems :: BL.ByteString -> [SearchResult]
getItems str =
let parsed = decode str :: Maybe JItems
in maybe [] getResults parsed
where
getResults (JItems xs) = map getResult xs
getResult x = SearchResult (jtitle . snippet $ x)
(jdescription . snippet $ x)
(makeURL . videoID . jvideoID $ x)
(jurl . thumbnail . jthumbnails . snippet $ x)
cid = "571126085022-7ash7a48cdao0tesqe66ghtime34cfvo.apps.googleusercontent.com"
secret = "FjgeOtSZoJgU87FbuwJf2vwj"
file = "./tokens.txt"
baseURI = "https://www.googleapis.com/youtube/v3/"
searchRequest :: String -> String -> String
searchRequest keyword accessTok =
baseURI ++
"search?part=snippet&q=" ++
keyword ++
"&type=video&access_token=" ++
accessTok
main = do
let client = OAuth2Client { clientId = cid, clientSecret = secret }
permissionUrl = formUrl client ["https://www.googleapis.com/auth/youtube"]
b <- doesFileExist file
unless b $ do
putStrLn $ "Load this URL: " ++ show permissionUrl
putStrLn "Please paste the verification code: "
authcode <- getLine
tokens <- exchangeCode client authcode
putStrLn $ "Received access token: " ++ show (accessToken tokens)
writeFile file (show tokens)
accessTok <- fmap (accessToken . read) (readFile file)
tracks <- findTracks client accessTok "Foo+Fighters"
print tracks
getNewTokens :: OAuth2Client -> IO ()
getNewTokens client = do
tokens <- read <$> readFile file
newTokens <- refreshTokens client tokens
writeFile file (show newTokens)
findTracks client accessTok term = do
response <- (try $ simpleHttp $ searchRequest term accessTok) :: IO (Either HttpException BL.ByteString)
case response of
(Left _) -> getNewTokens client >> findTracks client accessTok term
(Right resp) -> return $ getItems resp
search :: String -> [T.Text]
search term = undefined