Skip to content

Commit

Permalink
feat: CAU notice watcher
Browse files Browse the repository at this point in the history
  • Loading branch information
jhaemin committed May 10, 2020
1 parent 3e1381c commit 05fc84f
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 29 deletions.
146 changes: 146 additions & 0 deletions src/modules/cau-notice-watcher/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import Browser from 'zombie'
import EodiroMailer from '../eodiro-mailer'
import { JSDOM as JsDom } from 'jsdom'
import appRoot from 'app-root-path'
import fs from 'fs'
import wait from '../wait'

export type TitleBuilder = (
/** A single notice item */ noticeItemElement: HTMLElement | Element
) => string

export type FeedOptions = {
/**
* Minutes
* @default 10
*/
interval?: number
}

export interface Subscriber {
id: string
link: string
noticeItemSelector: string
titleBuilder: TitleBuilder
}

export type LastNotice = Record<string, string>

const lastNoticeFilePath = appRoot.resolve('/.eodiro/last_notice.json')

export class CauNoticeWatcher {
private feedOptions: FeedOptions
private subscribers: Subscriber[] = []
private shouldStop = false
private browser: any
private lastNotice: LastNotice

constructor(feedOptions?: FeedOptions) {
if (!feedOptions) {
feedOptions = {
interval: 10,
}
} else if (!feedOptions?.interval) {
feedOptions.interval = 10
}

this.feedOptions = feedOptions
this.browser = new Browser()
this.lastNotice = this.loadLastNoticeFile()
}

private loadLastNoticeFile() {
let lastNotice: LastNotice

if (!fs.existsSync(lastNoticeFilePath)) {
lastNotice = {}
fs.writeFileSync(lastNoticeFilePath, JSON.stringify(lastNotice, null, 2))
} else {
lastNotice = JSON.parse(fs.readFileSync(lastNoticeFilePath, 'utf8'))
}

return lastNotice
}

private writeLastNoticeFile() {
fs.writeFileSync(
lastNoticeFilePath,
JSON.stringify(this.lastNotice, null, 2)
)
}

private getLastNotice(subscriber: Subscriber) {
return this.lastNotice[subscriber.id]
}

private updateLastNotice(subscriber: Subscriber, title: string) {
this.lastNotice[subscriber.id] = title
}

public subscribe(subscriber: Subscriber) {
this.subscribers.push(subscriber)
}

public async watch() {
if (this.shouldStop) {
return
}

for (const subscriber of this.subscribers) {
await this.processSubscriber(subscriber)
}

// Recursive function call after the interval
await wait(this.feedOptions.interval * 60 * 1000)
this.watch()
}

private async processSubscriber(subscriber: Subscriber) {
const notices = Array.from(await this.visit(1, subscriber))

if (notices.length === 0) {
return
}

const lastNoticeIndex = notices.indexOf(this.getLastNotice(subscriber))
if (lastNoticeIndex !== -1) {
for (let i = lastNoticeIndex - 1; i >= 0; i--) {
EodiroMailer.sendMail({
from: '"어디로 알림" <[email protected]>',
to: '[email protected]',
subject: notices[i],
})
}
}

this.updateLastNotice(subscriber, notices[0])
this.writeLastNoticeFile()
}

private async visit(
page: number,
subscriber: Subscriber
): Promise<Set<string>> {
return new Promise((resolve) => {
const notices: Set<string> = new Set()

this.browser.visit(subscriber.link, null, () => {
const body = new JsDom(this.browser.html(subscriber.noticeItemSelector))
.window.document.body
const noticeElms = body.querySelectorAll(subscriber.noticeItemSelector)

for (const noticeElm of Array.from(noticeElms)) {
const title = subscriber.titleBuilder(noticeElm) || ''

notices.add(title)
}

resolve(notices)
})
})
}

public stop() {
this.shouldStop = true
}
}
13 changes: 13 additions & 0 deletions src/modules/cau-notice-watcher/subscribers/cau.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Subscriber } from '..'

export const cau: Subscriber = {
id: 'cau',
link: 'https://www.cau.ac.kr/cms/FR_CON/index.do?MENU_ID=100#page1',
noticeItemSelector: '.typeNoti',
titleBuilder: (noticeElm) => {
const mark = noticeElm.querySelector('.mark_noti').textContent.trim()
const title = noticeElm.querySelector('a').textContent.trim()

return `${mark} ${title}`
},
}
1 change: 1 addition & 0 deletions src/modules/cau-notice-watcher/subscribers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './cau'
21 changes: 0 additions & 21 deletions src/modules/eodiro-bot/cau-notice-rss-feed.ts

This file was deleted.

12 changes: 8 additions & 4 deletions src/modules/eodiro-bot/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import * as Subscribers from '@/modules/cau-notice-watcher/subscribers'

import { UserAttrs, getUser } from '@/database/models/user'

import { CTTS } from '@payw/cau-timetable-scraper'
import CafeteriaMenusSeeder from '@/db/seeders/cafeteria-menus-seeder'
import { CauNoticeWatcher } from '../cau-notice-watcher'
import Config from '@/config'
import { CronJob } from 'cron'
import Db from '@/db'
import EodiroMailer from '../eodiro-mailer'
import { cauNoticeRssFeed } from './cau-notice-rss-feed'
import chalk from 'chalk'
import dayjs from 'dayjs'
import { garbageCollectFiles } from './garbage-collect-files'
Expand All @@ -32,11 +34,13 @@ export default class EodiroBot {
// this.scrapeLectures()
this.scrapeCafeteriaMenus()
this.garbageCollect()
this.cauNoticeRssFeed()
this.cauNotice()
}

private cauNoticeRssFeed() {
cauNoticeRssFeed()
private cauNotice() {
const feed = new CauNoticeWatcher()
feed.subscribe(Subscribers.cau)
feed.watch()
}

/**
Expand Down
10 changes: 6 additions & 4 deletions src/modules/eodiro-mailer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import chalk from 'chalk'
const log = console.log

interface MailOption {
/**
* "name" \<[email protected]\>
*/
from?: string
subject: string
to: string
html?: string
Expand Down Expand Up @@ -40,10 +44,8 @@ export default class EodiroMailer {
// TODO: Asynchronous
static sendMail(options: MailOption): void {
this.transporter.sendMail({
from: '"어디로" <[email protected]>',
subject: options.subject,
to: options.to,
html: options.html,
from: '"어디로" <[email protected]>',
...options,
})
}
}

0 comments on commit 05fc84f

Please sign in to comment.