Showing
3 changed files
with
90 additions
and
61 deletions
| ... | @@ -2,16 +2,16 @@ | ... | @@ -2,16 +2,16 @@ |
| 2 | * Created by junyoung on 2017. 4. 2.. | 2 | * Created by junyoung on 2017. 4. 2.. |
| 3 | */ | 3 | */ |
| 4 | 4 | ||
| 5 | -var request = require('request'); | 5 | +let request = require('request'); |
| 6 | -var cheerio = require('cheerio'); | 6 | +let cheerio = require('cheerio'); |
| 7 | -var Promise = require('promise'); | 7 | +let Promise = require('promise'); |
| 8 | -var readline = require('readline'); | 8 | +let readline = require('readline'); |
| 9 | -var https = require('https'); | 9 | +let https = require('https'); |
| 10 | -var querystring = require('querystring'); | 10 | +let querystring = require('querystring'); |
| 11 | -var fs = require('fs'); | 11 | +let fs = require('fs'); |
| 12 | 12 | ||
| 13 | 13 | ||
| 14 | -var j = request.jar(); | 14 | +let j = request.jar(); |
| 15 | request = request.defaults({jar: j}); | 15 | request = request.defaults({jar: j}); |
| 16 | 16 | ||
| 17 | 17 | ||
| ... | @@ -33,7 +33,11 @@ exports.login = function (id, pw) { | ... | @@ -33,7 +33,11 @@ exports.login = function (id, pw) { |
| 33 | timeout: 3000 | 33 | timeout: 3000 |
| 34 | }, function (err, res, body) { | 34 | }, function (err, res, body) { |
| 35 | if (err) { | 35 | if (err) { |
| 36 | - reject('클라스 요청 응답시간이 너무 길어요.'); | 36 | + if(err.code === 'ESOCKETTIMEDOUT'){ |
| 37 | + reject('클라스 요청 응답시간이 너무 길어요... ㅠㅠ'); | ||
| 38 | + } else { | ||
| 39 | + reject('알수없는 에러가 발생했어요!.'); | ||
| 40 | + } | ||
| 37 | } else if (j.getCookies("https://klas.khu.ac.kr").length === 0) { | 41 | } else if (j.getCookies("https://klas.khu.ac.kr").length === 0) { |
| 38 | reject('로그인에 실패했습니다!'); | 42 | reject('로그인에 실패했습니다!'); |
| 39 | } else { | 43 | } else { |
| ... | @@ -76,11 +80,11 @@ exports.getLecture = function () { | ... | @@ -76,11 +80,11 @@ exports.getLecture = function () { |
| 76 | exports.getLectureLink = function (getLectureBody) { | 80 | exports.getLectureLink = function (getLectureBody) { |
| 77 | 81 | ||
| 78 | return new Promise(function (resolve, reject) { | 82 | return new Promise(function (resolve, reject) { |
| 79 | - var $ = cheerio.load(getLectureBody); | 83 | + let $ = cheerio.load(getLectureBody); |
| 80 | - var lectureLinks = $('.gomy_class'); | 84 | + let lectureLinks = $('.gomy_class'); |
| 81 | - var tableTrs = $('#tbl > tbody > tr > td'); | 85 | + let tableTrs = $('#tbl > tbody > tr > td'); |
| 82 | 86 | ||
| 83 | - var lectureLinkList = []; | 87 | + let lectureLinkList = []; |
| 84 | 88 | ||
| 85 | tableTrs.each(function (i) { | 89 | tableTrs.each(function (i) { |
| 86 | if (i % 7 === 1) { | 90 | if (i % 7 === 1) { |
| ... | @@ -94,7 +98,6 @@ exports.getLectureLink = function (getLectureBody) { | ... | @@ -94,7 +98,6 @@ exports.getLectureLink = function (getLectureBody) { |
| 94 | lectureLinkList[i].link = 'https://klas.khu.ac.kr' + $(this).attr('href') | 98 | lectureLinkList[i].link = 'https://klas.khu.ac.kr' + $(this).attr('href') |
| 95 | }); | 99 | }); |
| 96 | 100 | ||
| 97 | - console.log(lectureLinkList); | ||
| 98 | resolve(lectureLinkList); | 101 | resolve(lectureLinkList); |
| 99 | 102 | ||
| 100 | }) | 103 | }) |
| ... | @@ -114,13 +117,13 @@ exports.selectLecture = function (lectureLinkList) { | ... | @@ -114,13 +117,13 @@ exports.selectLecture = function (lectureLinkList) { |
| 114 | input: process.stdin, | 117 | input: process.stdin, |
| 115 | output: process.stdout | 118 | output: process.stdout |
| 116 | }); | 119 | }); |
| 117 | - var selectQuestion = ''; | 120 | + let selectQuestion = ''; |
| 118 | - selectQuestion += '\n 강의자료를 다운받을 강의를 선택해 주세요 \n'; | 121 | + selectQuestion += '\n 강의자료를 다운받을 강의를 선택해 주세요 :D\n\n'; |
| 119 | - var count = 0; | 122 | + let count = 0; |
| 120 | 123 | ||
| 121 | return new Promise(function (resolve, reject) { | 124 | return new Promise(function (resolve, reject) { |
| 122 | 125 | ||
| 123 | - for (var i in lectureLinkList) { | 126 | + for (let i in lectureLinkList) { |
| 124 | count += 1; | 127 | count += 1; |
| 125 | selectQuestion += ' ' + count + '. ' + lectureLinkList[i].lectureName + '\n'; | 128 | selectQuestion += ' ' + count + '. ' + lectureLinkList[i].lectureName + '\n'; |
| 126 | } | 129 | } |
| ... | @@ -139,13 +142,19 @@ exports.selectLecture = function (lectureLinkList) { | ... | @@ -139,13 +142,19 @@ exports.selectLecture = function (lectureLinkList) { |
| 139 | 142 | ||
| 140 | }; | 143 | }; |
| 141 | 144 | ||
| 145 | +/** | ||
| 146 | + * @author sungjunyoung | ||
| 147 | + * @description 강의실 링크의 url 을 받아서 HTML 를 리턴해주는 함수 | ||
| 148 | + * @param {String} lectureLink - 강의실 URL | ||
| 149 | + * @returns {*|Promise} | ||
| 150 | + */ | ||
| 142 | exports.getClassPageBody = function (lectureLink) { | 151 | exports.getClassPageBody = function (lectureLink) { |
| 143 | 152 | ||
| 144 | return new Promise(function (resolve, reject) { | 153 | return new Promise(function (resolve, reject) { |
| 145 | 154 | ||
| 146 | - var url = lectureLink.link; | 155 | + let url = lectureLink.link; |
| 147 | 156 | ||
| 148 | - var headers = { | 157 | + let headers = { |
| 149 | 'Cookie': 'COURSE_MENU_NAME=%uAC15%uC758%uC2E4', | 158 | 'Cookie': 'COURSE_MENU_NAME=%uAC15%uC758%uC2E4', |
| 150 | 'User-Agent': 'request' | 159 | 'User-Agent': 'request' |
| 151 | }; | 160 | }; |
| ... | @@ -154,10 +163,15 @@ exports.getClassPageBody = function (lectureLink) { | ... | @@ -154,10 +163,15 @@ exports.getClassPageBody = function (lectureLink) { |
| 154 | url: url, | 163 | url: url, |
| 155 | mothod: 'GET', | 164 | mothod: 'GET', |
| 156 | jar: j, | 165 | jar: j, |
| 157 | - headers: headers | 166 | + headers: headers, |
| 167 | + timeout: 3000 | ||
| 158 | }, function (err, res, body) { | 168 | }, function (err, res, body) { |
| 159 | if (err) { | 169 | if (err) { |
| 160 | - reject(err); | 170 | + if(err.code === 'ESOCKETTIMEDOUT'){ |
| 171 | + reject('클라스 요청 응답시간이 너무 길어요... ㅠㅠ'); | ||
| 172 | + } else { | ||
| 173 | + reject('알수없는 에러가 발생했어요!.'); | ||
| 174 | + } | ||
| 161 | } else { | 175 | } else { |
| 162 | resolve(body); | 176 | resolve(body); |
| 163 | } | 177 | } |
| ... | @@ -165,46 +179,64 @@ exports.getClassPageBody = function (lectureLink) { | ... | @@ -165,46 +179,64 @@ exports.getClassPageBody = function (lectureLink) { |
| 165 | }); | 179 | }); |
| 166 | }; | 180 | }; |
| 167 | 181 | ||
| 182 | +/** | ||
| 183 | + * @author sungjunyoung | ||
| 184 | + * @description 강의실 URL 페이지 HTML 을 받아와서 파일 다운로드 링크의 URL 어레이를 리턴 chapterFilesArr[{chapter, files[{link, fileName}]}] | ||
| 185 | + * @param {String} classPageBody - 강의실 URL 의 페이지 HTML | ||
| 186 | + * @returns {*|Promise} | ||
| 187 | + */ | ||
| 168 | exports.findFiles = function (classPageBody) { | 188 | exports.findFiles = function (classPageBody) { |
| 169 | 189 | ||
| 170 | return new Promise(function (resolve, reject) { | 190 | return new Promise(function (resolve, reject) { |
| 171 | - var $ = cheerio.load(classPageBody); | 191 | + let $ = cheerio.load(classPageBody); |
| 172 | - var fileDownAnchors = $('.mycl_listbox.today'); | 192 | + let fileDownAnchors = $('.mycl_listbox.today'); |
| 173 | - | ||
| 174 | - var fileArr = []; | ||
| 175 | 193 | ||
| 194 | + let chapterFilesArr = []; | ||
| 176 | 195 | ||
| 177 | fileDownAnchors.each(function (i) { | 196 | fileDownAnchors.each(function (i) { |
| 178 | - var tempFileArr = []; | 197 | + let chapter = $(this).find('.lf').text(); |
| 198 | + let tempChapterObj = {chapter: chapter, files: []}; | ||
| 179 | $(this).find('.mycl_veiw_learnig').find('.file-downbox-list').find('a').each(function (j) { | 199 | $(this).find('.mycl_veiw_learnig').find('.file-downbox-list').find('a').each(function (j) { |
| 180 | - var link = 'https://klas.khu.ac.kr' + $(this).attr('href').split('..')[1]; | 200 | + let link = 'https://klas.khu.ac.kr' + $(this).attr('href').split('..')[1]; |
| 181 | - tempFileArr.push(link); | 201 | + let fileName = $(this).text(); |
| 202 | + tempChapterObj.files.push({link: link, fileName: fileName}); | ||
| 182 | }); | 203 | }); |
| 183 | - fileArr.push(tempFileArr); | 204 | + chapterFilesArr.push(tempChapterObj); |
| 184 | }); | 205 | }); |
| 185 | 206 | ||
| 186 | - resolve(fileArr); | 207 | + resolve(chapterFilesArr); |
| 187 | }); | 208 | }); |
| 188 | }; | 209 | }; |
| 189 | 210 | ||
| 190 | -exports.getSelectedFiles = function (fileArr, lb) { | 211 | +/** |
| 191 | - | 212 | + * @author sungjunyoung |
| 192 | - return new Promise(function (resolve, reject) { | 213 | + * @description findFiles 의 chapterFilesArr[{chapter, files[{link, fileName}]}] 을 받아 사용자에게 선택하게 하고, 다운받아야 할 강의자료 리스트를 리턴 |
| 193 | - | 214 | + * @param {String} chapterFilesArr - 챕터별로 파일들과 파일 명의 리스트를 가지고 있는 리스트 |
| 194 | - var lectureBefore = 0; | 215 | + * @returns {*|Promise} |
| 195 | - if(!lb || lb === ''){ | 216 | + */ |
| 196 | - lectureBefore = 0; | 217 | +exports.selectChapter = function (chapterFilesArr) { |
| 197 | - } else { | ||
| 198 | - lectureBefore = lb; | ||
| 199 | - } | ||
| 200 | - | ||
| 201 | - var downloadIndex = fileArr.length - lectureBefore - 1; | ||
| 202 | 218 | ||
| 203 | - if (downloadIndex < 0) { | 219 | + const rl = readline.createInterface({ |
| 204 | - reject('이 날에는 강의자료가 없네요!'); | 220 | + input: process.stdin, |
| 205 | - } | 221 | + output: process.stdout |
| 222 | + }); | ||
| 223 | + let selectQuestion = ''; | ||
| 224 | + selectQuestion += '\n 강의자료를 다운받을 챕터를 선택해 주세요 :) \n\n'; | ||
| 225 | + let counter = 0; | ||
| 226 | + for (let i in chapterFilesArr) { | ||
| 227 | + counter = i * 1 + 1; | ||
| 228 | + selectQuestion += ' ' + counter + '. ' + chapterFilesArr[i].chapter; | ||
| 229 | + selectQuestion += '\n'; | ||
| 230 | + } | ||
| 231 | + selectQuestion += '\n'; | ||
| 232 | + selectQuestion += ' 입력 (1 ~ ' + counter + ') : '; | ||
| 206 | 233 | ||
| 207 | - resolve(fileArr[downloadIndex]); | 234 | + return new Promise(function (resolve, reject) { |
| 235 | + rl.question(selectQuestion, (answer) => { | ||
| 236 | + answer = parseInt(answer) - 1; | ||
| 237 | + resolve(chapterFilesArr[answer]); | ||
| 238 | + rl.close(); | ||
| 239 | + }); | ||
| 208 | }); | 240 | }); |
| 209 | }; | 241 | }; |
| 210 | 242 | ||
| ... | @@ -212,8 +244,8 @@ exports.downloadSelectedFile = function (selectedFile, path) { | ... | @@ -212,8 +244,8 @@ exports.downloadSelectedFile = function (selectedFile, path) { |
| 212 | 244 | ||
| 213 | return new Promise(function (resolve, reject) { | 245 | return new Promise(function (resolve, reject) { |
| 214 | 246 | ||
| 215 | - var downloadPath; | 247 | + let downloadPath; |
| 216 | - if(!path || path === ''){ | 248 | + if (!path || path === '') { |
| 217 | downloadPath = ''; | 249 | downloadPath = ''; |
| 218 | //TODO Default Path 설정하기 | 250 | //TODO Default Path 설정하기 |
| 219 | } else { | 251 | } else { |
| ... | @@ -221,12 +253,12 @@ exports.downloadSelectedFile = function (selectedFile, path) { | ... | @@ -221,12 +253,12 @@ exports.downloadSelectedFile = function (selectedFile, path) { |
| 221 | //TODO 사용자가 지정한 path 리포맷하기 | 253 | //TODO 사용자가 지정한 path 리포맷하기 |
| 222 | } | 254 | } |
| 223 | 255 | ||
| 224 | - var count = 0; | 256 | + let count = 0; |
| 225 | selectedFile.forEach(function (value, index) { | 257 | selectedFile.forEach(function (value, index) { |
| 226 | 258 | ||
| 227 | request = https.get(value, function (response) { | 259 | request = https.get(value, function (response) { |
| 228 | - count ++; | 260 | + count++; |
| 229 | - var file = fs.createWriteStream("./file_" + index + ".pdf"); | 261 | + let file = fs.createWriteStream("./file_" + index + ".pdf"); |
| 230 | response.pipe(file); | 262 | response.pipe(file); |
| 231 | 263 | ||
| 232 | if (index === count) { | 264 | if (index === count) { | ... | ... |
| ... | @@ -11,7 +11,7 @@ if(require.main === module){ | ... | @@ -11,7 +11,7 @@ if(require.main === module){ |
| 11 | 11 | ||
| 12 | args | 12 | args |
| 13 | .option('id', '[필수] 학번을 입력합니다.') | 13 | .option('id', '[필수] 학번을 입력합니다.') |
| 14 | - .option('pw', '[필수] 비밀번호를 입력합니다. 로컬 PC 에서만 사용하기 때문에 안전합니다 ^^.') | 14 | + .option('pw', '[필수] 비밀번호를 입력합니다. 로컬 PC 에서만 사용하기 때문에 안전합니다 :).') |
| 15 | .option('downloadPath', '[선택] 자료를 다운받을 경로를 입력합니다. (default 는 ~/Downloads 입니다.)'); | 15 | .option('downloadPath', '[선택] 자료를 다운받을 경로를 입력합니다. (default 는 ~/Downloads 입니다.)'); |
| 16 | 16 | ||
| 17 | const flags = args.parse(process.argv); | 17 | const flags = args.parse(process.argv); |
| ... | @@ -29,12 +29,9 @@ if(require.main === module){ | ... | @@ -29,12 +29,9 @@ if(require.main === module){ |
| 29 | .then(functions.selectLecture) | 29 | .then(functions.selectLecture) |
| 30 | .then(functions.getClassPageBody) | 30 | .then(functions.getClassPageBody) |
| 31 | .then(functions.findFiles) | 31 | .then(functions.findFiles) |
| 32 | - .then(function (fileArr) { | 32 | + .then(functions.selectChapter) |
| 33 | - return functions.getSelectedFiles(fileArr, flags.lectureBefore); | 33 | + .then(function(res){ |
| 34 | - }) | 34 | + console.log(res); |
| 35 | - .then(function (selectedFile) { | ||
| 36 | - // console.log(selectedFile); | ||
| 37 | - functions.downloadSelectedFile(selectedFile); | ||
| 38 | }) | 35 | }) |
| 39 | .catch(function (err) { | 36 | .catch(function (err) { |
| 40 | console.log(err); | 37 | console.log(err); | ... | ... |
| 1 | { | 1 | { |
| 2 | "name": "klas-file-downloader", | 2 | "name": "klas-file-downloader", |
| 3 | - "version": "0.0.3", | 3 | + "version": "0.0.4", |
| 4 | "description": "Project that download lecture reference files from Klas", | 4 | "description": "Project that download lecture reference files from Klas", |
| 5 | "main": "index.js", | 5 | "main": "index.js", |
| 6 | "scripts": { | 6 | "scripts": { |
| ... | @@ -22,7 +22,7 @@ | ... | @@ -22,7 +22,7 @@ |
| 22 | "url": "https://github.com/sungjunyoung/klas-file-downloader/issues" | 22 | "url": "https://github.com/sungjunyoung/klas-file-downloader/issues" |
| 23 | }, | 23 | }, |
| 24 | "bin": { | 24 | "bin": { |
| 25 | - "klasFileDownloader": "./index.js" | 25 | + "klasFD": "./index.js" |
| 26 | }, | 26 | }, |
| 27 | "homepage": "https://sungjunyoung.github.io", | 27 | "homepage": "https://sungjunyoung.github.io", |
| 28 | "dependencies": { | 28 | "dependencies": { | ... | ... |
-
Please register or login to post a comment