Add author to podcast template
This commit is contained in:
parent
549aec021e
commit
9690477272
|
@ -10,8 +10,8 @@
|
||||||
<description>{{audiobook-description}}</description>
|
<description>{{audiobook-description}}</description>
|
||||||
<language>it-it</language>
|
<language>it-it</language>
|
||||||
<lastBuildDate>{{pub-day}}</lastBuildDate>
|
<lastBuildDate>{{pub-day}}</lastBuildDate>
|
||||||
<itunes:author>Ad Alta Voce - Rai Radio 3</itunes:author>
|
<itunes:author>{{audiobook-author}}</itunes:author>
|
||||||
<itunes:summary>{{audiobook-description}}</itunes:summary>
|
<itunes:summary>{{audiobook-summary}}</itunes:summary>
|
||||||
<itunes:subtitle>Ad Alta Voce</itunes:subtitle>
|
<itunes:subtitle>Ad Alta Voce</itunes:subtitle>
|
||||||
<itunes:explicit>No</itunes:explicit>
|
<itunes:explicit>No</itunes:explicit>
|
||||||
<itunes:image href="https://www.raiplayradio.it/{{audiobook-cover-url}}"/>
|
<itunes:image href="https://www.raiplayradio.it/{{audiobook-cover-url}}"/>
|
||||||
|
|
|
@ -14,33 +14,36 @@ module Command.All(generateAll) where
|
||||||
import Control.Monad ( join )
|
import Control.Monad ( join )
|
||||||
import Data.Maybe ( catMaybes )
|
import Data.Maybe ( catMaybes )
|
||||||
import Text.HTML.Scalpel ( scrapeURL, URL )
|
import Text.HTML.Scalpel ( scrapeURL, URL )
|
||||||
import Command.Single ( single )
|
import Command.Single ( singleWithAuthor )
|
||||||
import Scraper.Playlist
|
import Scraper.Playlist
|
||||||
( playlistPageNumbersScraper, playlistsUrlScraper )
|
( playlistPageNumbersScraper, playlistInfosScraper )
|
||||||
|
|
||||||
baseUrl = "https://www.raiplayradio.it"
|
baseUrl = "https://www.raiplayradio.it"
|
||||||
playlistBaseUrl = "https://www.raiplayradio.it/programmi/adaltavoce/archivio/audiolibri/tutte/"
|
playlistBaseUrl = "https://www.raiplayradio.it/programmi/adaltavoce/archivio/audiolibri/tutte/"
|
||||||
|
|
||||||
scrapeAudiobooksUrl :: IO (Maybe [URL])
|
scrapeAudiobooksUrl :: IO (Maybe [(URL, String)])
|
||||||
scrapeAudiobooksUrl = do
|
scrapeAudiobooksUrl = do
|
||||||
pageNumbers <- scrapeURL playlistBaseUrl playlistPageNumbersScraper
|
pageNumbers <- scrapeURL playlistBaseUrl playlistPageNumbersScraper
|
||||||
case scrapePlaylistPages pageNumbers of
|
case scrapePlaylistPages pageNumbers of
|
||||||
Nothing -> return Nothing
|
Nothing -> return Nothing
|
||||||
Just urls -> Just <$> urls
|
Just urls -> Just <$> urls
|
||||||
|
|
||||||
scrapePlaylistPages :: Maybe [String] -> Maybe (IO [URL])
|
scrapePlaylistPages :: Maybe [String] -> Maybe (IO [(URL, String)])
|
||||||
scrapePlaylistPages pageNumbers = do
|
scrapePlaylistPages pageNumbers = do
|
||||||
pageNumbers' <- pageNumbers
|
pageNumbers' <- pageNumbers
|
||||||
let playlistUrls = map (playlistBaseUrl ++) pageNumbers'
|
let playlistUrls = map (playlistBaseUrl ++) pageNumbers'
|
||||||
audiobookUrls = mapM (`scrapeURL` playlistsUrlScraper) playlistUrls
|
audiobookInfos = mapM (`scrapeURL` playlistInfosScraper) playlistUrls
|
||||||
flatAudiobookUrls = join . catMaybes <$> audiobookUrls
|
flatAudiobookInfos = join . catMaybes <$> audiobookInfos
|
||||||
return $ map (baseUrl ++) <$> flatAudiobookUrls
|
return $ map (\(u, a) -> (concatBaseUrl u, a)) <$> flatAudiobookInfos
|
||||||
|
where
|
||||||
|
concatBaseUrl :: URL -> URL
|
||||||
|
concatBaseUrl = (++) baseUrl
|
||||||
|
|
||||||
generateAll :: String -> IO ()
|
generateAll :: String -> IO ()
|
||||||
generateAll outdir = do
|
generateAll outdir = do
|
||||||
urls <- scrapeAudiobooksUrl
|
infos <- scrapeAudiobooksUrl
|
||||||
case urls of
|
case infos of
|
||||||
Nothing -> putStrLn "Error"
|
Nothing -> putStrLn "Error"
|
||||||
Just urls' -> do
|
Just infos' -> do
|
||||||
mapM_ (`single` outdir) urls'
|
mapM_ (\(url, author) -> singleWithAuthor url outdir author) infos'
|
||||||
putStrLn "All done.\nEnjoy your books!"
|
putStrLn "All done.\nEnjoy your books!"
|
||||||
|
|
|
@ -9,7 +9,7 @@ This module exposes the command that generates podcast feed for an audiobooks
|
||||||
in Ad Alta Voce library.
|
in Ad Alta Voce library.
|
||||||
-}
|
-}
|
||||||
|
|
||||||
module Command.Single(single) where
|
module Command.Single(single, singleWithAuthor) where
|
||||||
|
|
||||||
import Data.Text (unpack)
|
import Data.Text (unpack)
|
||||||
import Data.Time.Clock ( UTCTime(utctDay), getCurrentTime )
|
import Data.Time.Clock ( UTCTime(utctDay), getCurrentTime )
|
||||||
|
@ -46,13 +46,21 @@ writePodcastTemplate (Right template) (Just podcast) outdir = do
|
||||||
fileName = outdir ++ "/" ++ generatePodcastFileName podcast
|
fileName = outdir ++ "/" ++ generatePodcastFileName podcast
|
||||||
output = title ++ " done!"
|
output = title ++ " done!"
|
||||||
|
|
||||||
single :: String -> String -> IO ()
|
single' :: Maybe Audiobook -> String -> String -> IO ()
|
||||||
single url outdir = do
|
single' audiobook url outdir = do
|
||||||
day <- utctDay <$> getCurrentTime
|
day <- utctDay <$> getCurrentTime
|
||||||
audiobook <- scrapeAudiobook url
|
|
||||||
compiled <- compilePodcastTemplate
|
compiled <- compilePodcastTemplate
|
||||||
|
|
||||||
let podcast = generatePodcast day url <$> audiobook
|
let podcast = generatePodcast day url <$> audiobook
|
||||||
|
|
||||||
writePodcastTemplate compiled podcast outdir
|
writePodcastTemplate compiled podcast outdir
|
||||||
|
|
||||||
|
single :: String -> String -> IO ()
|
||||||
|
single url outdir = do
|
||||||
|
audiobook <- scrapeAudiobook url
|
||||||
|
single' audiobook url outdir
|
||||||
|
|
||||||
|
singleWithAuthor :: String -> String -> String -> IO ()
|
||||||
|
singleWithAuthor url outdir author = do
|
||||||
|
audiobook <- scrapeAudiobook url
|
||||||
|
let abookDescription = (`toAudiobookWithAuthor` author) <$> audiobook
|
||||||
|
single' abookDescription url outdir
|
||||||
|
|
|
@ -16,7 +16,7 @@ An example of a web page that can be scraped is available at the following
|
||||||
module Scraper.Audiobook(audiobookScraper) where
|
module Scraper.Audiobook(audiobookScraper) where
|
||||||
|
|
||||||
import Text.HTML.Scalpel
|
import Text.HTML.Scalpel
|
||||||
import Types ( Audiobook(Audiobook), Episode(Episode) )
|
import Types
|
||||||
|
|
||||||
audiobookHeaderSelector :: Selector
|
audiobookHeaderSelector :: Selector
|
||||||
audiobookHeaderSelector = "div" @: [hasClass "descriptionProgramma"]
|
audiobookHeaderSelector = "div" @: [hasClass "descriptionProgramma"]
|
||||||
|
@ -75,4 +75,4 @@ audiobookScraper = do
|
||||||
description <- audiobookDescriptionScraper
|
description <- audiobookDescriptionScraper
|
||||||
coverUrl <- audiobookCoverUrlScraper
|
coverUrl <- audiobookCoverUrlScraper
|
||||||
episodes <- episodesListScraper
|
episodes <- episodesListScraper
|
||||||
return $ Audiobook title description coverUrl episodes
|
return $ makeAudiobook title description coverUrl episodes
|
||||||
|
|
|
@ -14,8 +14,8 @@ An example of a web page that can be scraped is available at the following
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
module Scraper.Playlist
|
module Scraper.Playlist
|
||||||
( playlistsUrlScraper
|
( playlistPageNumbersScraper
|
||||||
, playlistPageNumbersScraper
|
, playlistInfosScraper
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Text.HTML.Scalpel
|
import Text.HTML.Scalpel
|
||||||
|
@ -26,10 +26,22 @@ playlistSelector = "div" @: [hasClass "bloccoPlaylist"]
|
||||||
playlistUrlScraper :: Scraper String String
|
playlistUrlScraper :: Scraper String String
|
||||||
playlistUrlScraper = attr "href" "a"
|
playlistUrlScraper = attr "href" "a"
|
||||||
|
|
||||||
|
playlistAuthorSelector :: Selector
|
||||||
|
playlistAuthorSelector = "span" @: [hasClass "canale"]
|
||||||
|
|
||||||
|
playlistAuthorScraper :: Scraper String String
|
||||||
|
playlistAuthorScraper = text playlistAuthorSelector
|
||||||
|
|
||||||
|
playlistInfoScraper :: Scraper String (String, String)
|
||||||
|
playlistInfoScraper = do
|
||||||
|
url <- playlistUrlScraper
|
||||||
|
author <- playlistAuthorScraper
|
||||||
|
return (url, author)
|
||||||
|
|
||||||
-- |The 'playlistUrlScraper' function defines the scraper that retrieves all
|
-- |The 'playlistUrlScraper' function defines the scraper that retrieves all
|
||||||
-- audiobooks url cointains in the playlist page.
|
-- audiobooks url and author cointains in the playlist page.
|
||||||
playlistsUrlScraper :: Scraper String [String]
|
playlistInfosScraper :: Scraper String [(String, String)]
|
||||||
playlistsUrlScraper = chroots playlistSelector playlistUrlScraper
|
playlistInfosScraper = chroots playlistSelector playlistInfoScraper
|
||||||
|
|
||||||
playlistPageNumberSelector :: Selector
|
playlistPageNumberSelector :: Selector
|
||||||
playlistPageNumberSelector = "ul" @: [hasClass "pagination"]
|
playlistPageNumberSelector = "ul" @: [hasClass "pagination"]
|
||||||
|
|
19
src/Types.hs
19
src/Types.hs
|
@ -12,9 +12,12 @@ their fields.
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
module Types
|
module Types
|
||||||
( Audiobook(Audiobook)
|
( Audiobook
|
||||||
, Episode(Episode)
|
, Episode(Episode)
|
||||||
, Podcast(Podcast)
|
, Podcast(Podcast)
|
||||||
|
, makeAudiobook
|
||||||
|
, makeAudiobookWithAuthor
|
||||||
|
, toAudiobookWithAuthor
|
||||||
, generatePodcast
|
, generatePodcast
|
||||||
, episodeUrl
|
, episodeUrl
|
||||||
, episodeTitle
|
, episodeTitle
|
||||||
|
@ -25,6 +28,7 @@ module Types
|
||||||
, audiobookDescription
|
, audiobookDescription
|
||||||
, audiobookCoverUrl
|
, audiobookCoverUrl
|
||||||
, audiobookEpisodes
|
, audiobookEpisodes
|
||||||
|
, audiobookAuthor
|
||||||
, audiobook
|
, audiobook
|
||||||
, baseUrl
|
, baseUrl
|
||||||
, pubDay
|
, pubDay
|
||||||
|
@ -49,12 +53,23 @@ data Episode = Episode { episodeUrl :: String
|
||||||
-- | The 'Audiobook' data type represents the audiobook of the podcast.
|
-- | The 'Audiobook' data type represents the audiobook of the podcast.
|
||||||
-- 'Audiobook' is an istance of 'ToMustache' typeclass.
|
-- 'Audiobook' is an istance of 'ToMustache' typeclass.
|
||||||
data Audiobook = Audiobook { audiobookTitle :: String
|
data Audiobook = Audiobook { audiobookTitle :: String
|
||||||
|
, audiobookAuthor :: String
|
||||||
, audiobookDescription :: String
|
, audiobookDescription :: String
|
||||||
, audiobookCoverUrl :: String
|
, audiobookCoverUrl :: String
|
||||||
, audiobookEpisodes :: [Episode]
|
, audiobookEpisodes :: [Episode]
|
||||||
|
|
||||||
}
|
}
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
|
makeAudiobook :: String -> String -> String -> [Episode] -> Audiobook
|
||||||
|
makeAudiobook title = Audiobook title "Ad Alta Voce - Rai Radio 3"
|
||||||
|
|
||||||
|
makeAudiobookWithAuthor :: String -> String -> String -> String -> [Episode] -> Audiobook
|
||||||
|
makeAudiobookWithAuthor title author = Audiobook title (author ++ " - Ad Alta Voce")
|
||||||
|
|
||||||
|
toAudiobookWithAuthor :: Audiobook -> String -> Audiobook
|
||||||
|
toAudiobookWithAuthor (Audiobook title _ description coverUrl episodes) author =
|
||||||
|
makeAudiobookWithAuthor title author description coverUrl episodes
|
||||||
|
|
||||||
-- | The 'Podcast' data type represents the podcast.
|
-- | The 'Podcast' data type represents the podcast.
|
||||||
-- 'Podcast' is an istance of 'ToMustache' typeclass.
|
-- 'Podcast' is an istance of 'ToMustache' typeclass.
|
||||||
|
@ -70,6 +85,8 @@ toPairList audiobook =
|
||||||
, "audiobook-cover-url" ~> audiobookCoverUrl audiobook
|
, "audiobook-cover-url" ~> audiobookCoverUrl audiobook
|
||||||
, "audiobook-cover-title" ~> audiobookTitle audiobook
|
, "audiobook-cover-title" ~> audiobookTitle audiobook
|
||||||
, "audiobook-description" ~> audiobookDescription audiobook
|
, "audiobook-description" ~> audiobookDescription audiobook
|
||||||
|
, "audiobook-summary" ~> audiobookDescription audiobook
|
||||||
|
, "audiobook-author" ~> audiobookAuthor audiobook
|
||||||
, "episodes" ~> audiobookEpisodes audiobook
|
, "episodes" ~> audiobookEpisodes audiobook
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue