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.
 

122 lines
3.6 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)
import Data.Aeson
import qualified Data.ByteString.Lazy.Char8 as BL
import qualified Data.Text as T
import qualified Data.Map as M
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)
tokens2 <- refreshTokens client tokens
putStrLn $ "As a test, refreshed token: " ++ show (accessToken tokens2)
writeFile file (show tokens2)
accessTok <- fmap (accessToken . read) (readFile file)
findTracks accessTok "Foo+Fighters"
findTracks accessTok term = do
response <- simpleHttp $ searchRequest term accessTok
return $ getItems response
search :: String -> [T.Text]
search term = undefined