File size: 4,173 Bytes
58293b7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import cliProgress from "cli-progress"
import { puppeteerSg } from "../utils/request/PuppeteerSg.js";
import { pdfGenerator } from "../utils/io/PdfGenerator.js";
import { configLoader } from "../utils/io/ConfigLoader.js";
import { directoryIo } from "../utils/io/DirectoryIo.js"
import * as everandRegex from "../const/EverandRegex.js"
import { Image } from "../object/Image.js"
import sharp from "sharp";
import axios from "axios";
import fs from "fs"


const output = configLoader.load("DIRECTORY", "output")

class EverandDownloader {
    constructor() {
        if (!EverandDownloader.instance) {
            EverandDownloader.instance = this
        }
        return EverandDownloader.instance
    }

    async execute(url) {
        if (url.match(everandRegex.PODCAST_SERIES)) {
            await this.series(url, )
        } else if (url.match(everandRegex.PODCAST_EPISODE)) {
            await this.listen(`https://www.everand.com/listen/podcast/${everandRegex.PODCAST_EPISODE.exec(url)[1]}`)
        } else if (url.match(everandRegex.PODCAST_LISTEN)) {
            await this.listen(url)
        } else {
            throw new Error(`Unsupported URL: ${url}`)
        }
    }

    async listen(url, isEpisode) {
        if (typeof isEpisode === "undefined") {
            isEpisode = true
        }

        const episodeId = everandRegex.PODCAST_LISTEN.exec(url)[1]

        // navigate to everand
        let page = await puppeteerSg.getPage(url)

        // wait rendering
        await new Promise(resolve => setTimeout(resolve, 1000))

        // get title, audio-url, series-url
        const title = await page.evaluate(() => eval('Scribd.current_doc.short_title'))
        const audioUrl = await page.evaluate(() => document.querySelector('audio#audioplayer').src)
        const seriesUrl = await page.evaluate(() => document.querySelector('a[href^="https://www.everand.com/podcast-show/"]').href)

        // prepare output dir
        let seriesId = everandRegex.PODCAST_SERIES.exec(seriesUrl)[1]
        let dir = `${output}/${seriesId}`
        await directoryIo.create(dir)

        // download audio
        const bar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
        if (isEpisode) {
            bar.start(1, 0)
        }
        let path = `${dir}/${episodeId}_${title}.mp3`
        const resp = await axios.get(audioUrl, { responseType: 'stream' })
        resp.data.pipe(fs.createWriteStream(path))
        if (isEpisode) {
            bar.update(1)
            bar.stop()
        }

        await page.close()
        if (isEpisode) {
            await puppeteerSg.close()
        }
    }

    async series(url) {
        const seriesId = everandRegex.PODCAST_SERIES.exec(url)[1]

        // navigate to everand
        let page = await puppeteerSg.getPage(url)

        // wait rendering
        await new Promise(resolve => setTimeout(resolve, 1000))

        // get number-of-episodes
        const totalEpisode = await page.evaluate(() => parseInt(document.querySelector('span[data-e2e="podcast-series-header-total-episodes"]').textContent.replace("episodes", "").trim()))

        // get pages
        const totalPage = await page.evaluate(() => [...document.querySelectorAll('div[data-e2e="pagination"] a[aria-label^="Page"]')].at(-1).textContent)
        const bar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic)
        bar.start(totalEpisode, 0)
        xx:
        for (let i = 1; i <= totalPage; i++) {
            await page.goto(`${url}?page=${i}&sort=desc`, { waitUntil: "load" })
            await new Promise(resolve => setTimeout(resolve, 1000))

            let episodes = await page.evaluate(() => [...document.querySelectorAll('div.breakpoint_hide.below a[data-e2e="podcast-episode-player-button"]')].map(x => x.href))
            for (let j = 0; j < episodes.length; j++ ) {
                await this.listen(episodes[j], false)
                bar.update(((i - 1) * 10) + (j + 1))
                break xx
            }
        }
        bar.stop()

        await page.close()
        await puppeteerSg.close()
    }
}

export const everandDownloader = new EverandDownloader()