Showing
4 changed files
with
219 additions
and
47 deletions
| ... | @@ -5,7 +5,7 @@ | ... | @@ -5,7 +5,7 @@ |
| 5 | var request = require('request'); | 5 | var request = require('request'); |
| 6 | var cheerio = require('cheerio'); | 6 | var cheerio = require('cheerio'); |
| 7 | var Promise = require('promise'); | 7 | var Promise = require('promise'); |
| 8 | -const readline = require('readline'); | 8 | +var readline = require('readline'); |
| 9 | var https = require('https'); | 9 | var https = require('https'); |
| 10 | var querystring = require('querystring'); | 10 | var querystring = require('querystring'); |
| 11 | var fs = require('fs'); | 11 | var fs = require('fs'); |
| ... | @@ -14,6 +14,16 @@ var fs = require('fs'); | ... | @@ -14,6 +14,16 @@ var fs = require('fs'); |
| 14 | var j = request.jar(); | 14 | var j = request.jar(); |
| 15 | request = request.defaults({jar: j}); | 15 | request = request.defaults({jar: j}); |
| 16 | 16 | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * @author sungjunyoung | ||
| 20 | + * @description klas에 로그인해서 세션을 받습니다. | ||
| 21 | + * 3초가 넘게 응답이 없으면 klas 서버 오류, | ||
| 22 | + * 쿠키를 받지 못했을 경우 로그인 에러를 반환합니다. | ||
| 23 | + * @param id | ||
| 24 | + * @param pw | ||
| 25 | + * @returns {*|Promise} | ||
| 26 | + */ | ||
| 17 | exports.login = function (id, pw) { | 27 | exports.login = function (id, pw) { |
| 18 | return new Promise(function (resolve, reject) { | 28 | return new Promise(function (resolve, reject) { |
| 19 | request({ | 29 | request({ |
| ... | @@ -23,17 +33,22 @@ exports.login = function (id, pw) { | ... | @@ -23,17 +33,22 @@ exports.login = function (id, pw) { |
| 23 | timeout: 3000 | 33 | timeout: 3000 |
| 24 | }, function (err, res, body) { | 34 | }, function (err, res, body) { |
| 25 | if (err) { | 35 | if (err) { |
| 26 | - reject('timeout'); | 36 | + reject('클라스 요청 응답시간이 너무 길어요.'); |
| 27 | } else if (j.getCookies("https://klas.khu.ac.kr").length === 0) { | 37 | } else if (j.getCookies("https://klas.khu.ac.kr").length === 0) { |
| 28 | - reject('login_error'); | 38 | + reject('로그인에 실패했습니다!'); |
| 29 | } else { | 39 | } else { |
| 30 | - resolve(body); | 40 | + resolve('success'); |
| 31 | } | 41 | } |
| 32 | }) | 42 | }) |
| 33 | }); | 43 | }); |
| 34 | }; | 44 | }; |
| 35 | 45 | ||
| 36 | - | 46 | +/** |
| 47 | + * @author sungjunyoung | ||
| 48 | + * @description login 세션을 가지고 현재 수강중인 강의 리스트를 보여주는 페이지에 접근합니다. | ||
| 49 | + * 해당 페이지의 html 소스를 반환합니다. | ||
| 50 | + * @returns {*|Promise} | ||
| 51 | + */ | ||
| 37 | exports.getLecture = function () { | 52 | exports.getLecture = function () { |
| 38 | 53 | ||
| 39 | return new Promise(function (resolve, reject) { | 54 | return new Promise(function (resolve, reject) { |
| ... | @@ -42,7 +57,8 @@ exports.getLecture = function () { | ... | @@ -42,7 +57,8 @@ exports.getLecture = function () { |
| 42 | method: "GET" | 57 | method: "GET" |
| 43 | }, function (err, res, body) { | 58 | }, function (err, res, body) { |
| 44 | if (err) { | 59 | if (err) { |
| 45 | - reject(err); | 60 | + console.log(err); |
| 61 | + reject('파싱 중 에러가 발생했어요!'); | ||
| 46 | } else { | 62 | } else { |
| 47 | resolve(body); | 63 | resolve(body); |
| 48 | } | 64 | } |
| ... | @@ -50,6 +66,13 @@ exports.getLecture = function () { | ... | @@ -50,6 +66,13 @@ exports.getLecture = function () { |
| 50 | }) | 66 | }) |
| 51 | }; | 67 | }; |
| 52 | 68 | ||
| 69 | +/** | ||
| 70 | + * @author sungjunyoung | ||
| 71 | + * @description getLecture 에서 받은 페이지 소스에서 강의 이름과 강의실로 가는 링크를 파싱합니다. | ||
| 72 | + * lectureLinkList 에 오브젝트 리스트 형태로 결과를 반환합니다. | ||
| 73 | + * @param getLectureBody | ||
| 74 | + * @returns {*|Promise} | ||
| 75 | + */ | ||
| 53 | exports.getLectureLink = function (getLectureBody) { | 76 | exports.getLectureLink = function (getLectureBody) { |
| 54 | 77 | ||
| 55 | return new Promise(function (resolve, reject) { | 78 | return new Promise(function (resolve, reject) { |
| ... | @@ -71,11 +94,20 @@ exports.getLectureLink = function (getLectureBody) { | ... | @@ -71,11 +94,20 @@ exports.getLectureLink = function (getLectureBody) { |
| 71 | lectureLinkList[i].link = 'https://klas.khu.ac.kr' + $(this).attr('href') | 94 | lectureLinkList[i].link = 'https://klas.khu.ac.kr' + $(this).attr('href') |
| 72 | }); | 95 | }); |
| 73 | 96 | ||
| 97 | + console.log(lectureLinkList); | ||
| 74 | resolve(lectureLinkList); | 98 | resolve(lectureLinkList); |
| 75 | 99 | ||
| 76 | }) | 100 | }) |
| 77 | }; | 101 | }; |
| 78 | 102 | ||
| 103 | +/** | ||
| 104 | + * @author sungjunyoung | ||
| 105 | + * @description lectureLinkList [{lectureName (string), link (string)}] 를 받고 강의를 선택합니다. 그에대한 강의실 link (string) 를 리턴합니다. | ||
| 106 | + * @param {Object[]} lectureLinkList - 강좌명, 강의실을 포함하는 리스트들 | ||
| 107 | + * @param lectureLinkList[].lectureName - 강의명 [강의코드] | ||
| 108 | + * @param lectureLinkList[].link - 강의실 link | ||
| 109 | + * @returns {*|Promise} | ||
| 110 | + */ | ||
| 79 | exports.selectLecture = function (lectureLinkList) { | 111 | exports.selectLecture = function (lectureLinkList) { |
| 80 | 112 | ||
| 81 | const rl = readline.createInterface({ | 113 | const rl = readline.createInterface({ |
| ... | @@ -129,8 +161,8 @@ exports.getClassPageBody = function (lectureLink) { | ... | @@ -129,8 +161,8 @@ exports.getClassPageBody = function (lectureLink) { |
| 129 | } else { | 161 | } else { |
| 130 | resolve(body); | 162 | resolve(body); |
| 131 | } | 163 | } |
| 132 | - }) | 164 | + }); |
| 133 | - }) | 165 | + }); |
| 134 | }; | 166 | }; |
| 135 | 167 | ||
| 136 | exports.findFiles = function (classPageBody) { | 168 | exports.findFiles = function (classPageBody) { |
| ... | @@ -152,7 +184,7 @@ exports.findFiles = function (classPageBody) { | ... | @@ -152,7 +184,7 @@ exports.findFiles = function (classPageBody) { |
| 152 | }); | 184 | }); |
| 153 | 185 | ||
| 154 | resolve(fileArr); | 186 | resolve(fileArr); |
| 155 | - }) | 187 | + }); |
| 156 | }; | 188 | }; |
| 157 | 189 | ||
| 158 | exports.getSelectedFiles = function (fileArr, lb) { | 190 | exports.getSelectedFiles = function (fileArr, lb) { |
| ... | @@ -169,11 +201,11 @@ exports.getSelectedFiles = function (fileArr, lb) { | ... | @@ -169,11 +201,11 @@ exports.getSelectedFiles = function (fileArr, lb) { |
| 169 | var downloadIndex = fileArr.length - lectureBefore - 1; | 201 | var downloadIndex = fileArr.length - lectureBefore - 1; |
| 170 | 202 | ||
| 171 | if (downloadIndex < 0) { | 203 | if (downloadIndex < 0) { |
| 172 | - reject('no reference files'); | 204 | + reject('이 날에는 강의자료가 없네요!'); |
| 173 | } | 205 | } |
| 174 | 206 | ||
| 175 | resolve(fileArr[downloadIndex]); | 207 | resolve(fileArr[downloadIndex]); |
| 176 | - }) | 208 | + }); |
| 177 | }; | 209 | }; |
| 178 | 210 | ||
| 179 | exports.downloadSelectedFile = function (selectedFile, path) { | 211 | exports.downloadSelectedFile = function (selectedFile, path) { |
| ... | @@ -203,6 +235,6 @@ exports.downloadSelectedFile = function (selectedFile, path) { | ... | @@ -203,6 +235,6 @@ exports.downloadSelectedFile = function (selectedFile, path) { |
| 203 | 235 | ||
| 204 | }); | 236 | }); |
| 205 | 237 | ||
| 206 | - }) | ||
| 207 | - }) | ||
| 208 | -}; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 238 | + }); | ||
| 239 | + }); | ||
| 240 | +}; | ... | ... |
| ... | @@ -2,39 +2,62 @@ | ... | @@ -2,39 +2,62 @@ |
| 2 | 2 | ||
| 3 | var args = require('args'); | 3 | var args = require('args'); |
| 4 | var functions = require('./functions'); | 4 | var functions = require('./functions'); |
| 5 | -var os = require('os'); | 5 | +// var os = require('os'); |
| 6 | - | 6 | + |
| 7 | -args | 7 | + |
| 8 | - .option('id', '[필수] 학번을 입력합니다.') | 8 | + |
| 9 | - .option('pw', '[필수] 비밀번호를 입력합니다. 절대 악용되지 않습니다.') | 9 | +if(require.main === module){ |
| 10 | - .option('lectureBefore', '[선택] 몇번째 전 강좌의 자료를 다운받을지 선택합니다. Default 는 0 입니다.') | 10 | + // 커멘드 라인 상에서 직접적으로 불려졌을 때 |
| 11 | - .option('downloadPath', '[선택] 자료를 다운받을 경로를 선택합니다.'); | 11 | + |
| 12 | - | 12 | + args |
| 13 | -const flags = args.parse(process.argv); | 13 | + .option('id', '[필수] 학번을 입력합니다.') |
| 14 | - | 14 | + .option('pw', '[필수] 비밀번호를 입력합니다. 로컬 PC 에서만 사용하기 때문에 안전합니다 ^^.') |
| 15 | -if (!flags.id) { | 15 | + .option('downloadPath', '[선택] 자료를 다운받을 경로를 입력합니다. (default 는 ~/Downloads 입니다.)'); |
| 16 | - console.log('id is required!'); | 16 | + |
| 17 | - return; | 17 | + const flags = args.parse(process.argv); |
| 18 | -} else if (!flags.pw) { | 18 | + |
| 19 | - console.log('pw is required!'); | 19 | + if (!flags.id) { |
| 20 | - return; | 20 | + console.log('학번(id) 가 필요해요!'); |
| 21 | -} | 21 | + return; |
| 22 | + } else if (!flags.pw) { | ||
| 23 | + console.log('비밀번호(pw) 가 필요해요!'); | ||
| 24 | + return; | ||
| 25 | + } else { | ||
| 26 | + functions.login(flags.id, flags.pw) | ||
| 27 | + .then(functions.getLecture) | ||
| 28 | + .then(functions.getLectureLink) | ||
| 29 | + .then(functions.selectLecture) | ||
| 30 | + .then(functions.getClassPageBody) | ||
| 31 | + .then(functions.findFiles) | ||
| 32 | + .then(function (fileArr) { | ||
| 33 | + return functions.getSelectedFiles(fileArr, flags.lectureBefore); | ||
| 34 | + }) | ||
| 35 | + .then(function (selectedFile) { | ||
| 36 | + // console.log(selectedFile); | ||
| 37 | + functions.downloadSelectedFile(selectedFile); | ||
| 38 | + }) | ||
| 39 | + .catch(function (err) { | ||
| 40 | + console.log(err); | ||
| 41 | + }); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | +} else { | ||
| 45 | + // 모듈로 불려졌을때 (준비중) | ||
| 46 | + | ||
| 47 | + // module.exports = { | ||
| 48 | + // | ||
| 49 | + // getLectureList: function (id, pw, callback) { | ||
| 50 | + // functions.login(id, pw) | ||
| 51 | + // .then(functions.getLecture) | ||
| 52 | + // .then(functions.getLectureLink) | ||
| 53 | + // .then(function(lectureList){ | ||
| 54 | + // callback(lectureList); | ||
| 55 | + // }) | ||
| 56 | + // } | ||
| 57 | + // | ||
| 58 | + // }; | ||
| 22 | 59 | ||
| 60 | +} | ||
| 23 | 61 | ||
| 24 | -functions.login(flags.id, flags.pw) | ||
| 25 | - .then(functions.getLecture) | ||
| 26 | - .then(functions.getLectureLink) | ||
| 27 | - .then(functions.selectLecture) | ||
| 28 | - .then(functions.getClassPageBody) | ||
| 29 | - .then(functions.findFiles) | ||
| 30 | - .then(function (fileArr) { | ||
| 31 | - return functions.getSelectedFiles(fileArr, flags.lectureBefore); | ||
| 32 | - }) | ||
| 33 | - .then(function (selectedFile) { | ||
| 34 | - functions.downloadSelectedFile(selectedFile, flags.downloadPath); | ||
| 35 | - }) | ||
| 36 | - .catch(function (err) { | ||
| 37 | - console.log(err); | ||
| 38 | - }); | ||
| 39 | 62 | ||
| 40 | 63 | ... | ... |
npm-debug.log
0 → 100644
| 1 | +0 info it worked if it ends with ok | ||
| 2 | +1 verbose cli [ '/usr/local/Cellar/node/7.3.0/bin/node', | ||
| 3 | +1 verbose cli '/usr/local/bin/npm', | ||
| 4 | +1 verbose cli 'publish' ] | ||
| 5 | +2 info using npm@3.10.10 | ||
| 6 | +3 info using node@v7.3.0 | ||
| 7 | +4 verbose publish [ '.' ] | ||
| 8 | +5 silly cache add args [ '.', null ] | ||
| 9 | +6 verbose cache add spec . | ||
| 10 | +7 silly cache add parsed spec Result { | ||
| 11 | +7 silly cache add raw: '.', | ||
| 12 | +7 silly cache add scope: null, | ||
| 13 | +7 silly cache add escapedName: null, | ||
| 14 | +7 silly cache add name: null, | ||
| 15 | +7 silly cache add rawSpec: '.', | ||
| 16 | +7 silly cache add spec: '/Users/junyoung/Library/Mobile Documents/com~apple~CloudDocs/Junyoung/Opensource/klas-file-downloader', | ||
| 17 | +7 silly cache add type: 'directory' } | ||
| 18 | +8 verbose addLocalDirectory /Users/junyoung/.npm/klas-file-downloader/0.0.3/package.tgz not in flight; packing | ||
| 19 | +9 verbose correctMkdir /Users/junyoung/.npm correctMkdir not in flight; initializing | ||
| 20 | +10 info lifecycle klas-file-downloader@0.0.3~prepublish: klas-file-downloader@0.0.3 | ||
| 21 | +11 silly lifecycle klas-file-downloader@0.0.3~prepublish: no script for prepublish, continuing | ||
| 22 | +12 verbose tar pack [ '/Users/junyoung/.npm/klas-file-downloader/0.0.3/package.tgz', | ||
| 23 | +12 verbose tar pack '/Users/junyoung/Library/Mobile Documents/com~apple~CloudDocs/Junyoung/Opensource/klas-file-downloader' ] | ||
| 24 | +13 verbose tarball /Users/junyoung/.npm/klas-file-downloader/0.0.3/package.tgz | ||
| 25 | +14 verbose folder /Users/junyoung/Library/Mobile Documents/com~apple~CloudDocs/Junyoung/Opensource/klas-file-downloader | ||
| 26 | +15 verbose addLocalTarball adding from inside cache /Users/junyoung/.npm/klas-file-downloader/0.0.3/package.tgz | ||
| 27 | +16 verbose correctMkdir /Users/junyoung/.npm correctMkdir not in flight; initializing | ||
| 28 | +17 silly cache afterAdd klas-file-downloader@0.0.3 | ||
| 29 | +18 verbose afterAdd /Users/junyoung/.npm/klas-file-downloader/0.0.3/package/package.json not in flight; writing | ||
| 30 | +19 verbose correctMkdir /Users/junyoung/.npm correctMkdir not in flight; initializing | ||
| 31 | +20 verbose afterAdd /Users/junyoung/.npm/klas-file-downloader/0.0.3/package/package.json written | ||
| 32 | +21 silly publish { name: 'klas-file-downloader', | ||
| 33 | +21 silly publish version: '0.0.3', | ||
| 34 | +21 silly publish description: 'Project that download lecture reference files from Klas', | ||
| 35 | +21 silly publish main: 'index.js', | ||
| 36 | +21 silly publish scripts: { test: 'echo "Error: no test specified" && exit 1' }, | ||
| 37 | +21 silly publish repository: | ||
| 38 | +21 silly publish { type: 'git', | ||
| 39 | +21 silly publish url: 'git+https://github.com/sungjunyoung/klas-file-downloader.git' }, | ||
| 40 | +21 silly publish keywords: [ 'klas', 'file', 'download', 'lecture' ], | ||
| 41 | +21 silly publish author: { name: 'sungjunyoung' }, | ||
| 42 | +21 silly publish license: 'MIT', | ||
| 43 | +21 silly publish bugs: { url: 'https://github.com/sungjunyoung/klas-file-downloader/issues' }, | ||
| 44 | +21 silly publish bin: { klasFileDownloader: './index.js' }, | ||
| 45 | +21 silly publish homepage: 'https://sungjunyoung.github.io', | ||
| 46 | +21 silly publish dependencies: | ||
| 47 | +21 silly publish { args: '^2.4.1', | ||
| 48 | +21 silly publish cheerio: '^0.22.0', | ||
| 49 | +21 silly publish fs: '0.0.1-security', | ||
| 50 | +21 silly publish promise: '^7.1.1', | ||
| 51 | +21 silly publish querystring: '^0.2.0', | ||
| 52 | +21 silly publish request: '^2.81.0' }, | ||
| 53 | +21 silly publish readme: '\n> # **IN-DEVELOPING**\n\n# klas-file-downloader\n\n경희대학교 클라스의 강의실 페이지에서 강의자료를 다운받는 npm 패키지입니다.\n\n\n## INSTALL\n\n```\nnpm install -g klasFileDownloader \n```\n\n## USAGE\n\n> **WARNING!!** 패스워드가 @ 이외의 특수문자를 포함하고 있다면, 패스워드 앞에 \\ 를 붙여주어야 합니다. \n\n```\nklasFileDownloader -i 2012104095 -p \\!123123\\*123\n```\n\n\n---\nMIT License\n\nCopyright (c) 2017 Junyoung, Sung\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the "Software"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n', | ||
| 54 | +21 silly publish readmeFilename: 'README.md', | ||
| 55 | +21 silly publish gitHead: 'f63d4d6214ea2d6abbdf2787afa1b9261b9009ff', | ||
| 56 | +21 silly publish _id: 'klas-file-downloader@0.0.3', | ||
| 57 | +21 silly publish _shasum: 'caee90301dde3dc1d87971fb49149ab4276c4871', | ||
| 58 | +21 silly publish _from: '.' } | ||
| 59 | +22 verbose getPublishConfig undefined | ||
| 60 | +23 silly mapToRegistry name klas-file-downloader | ||
| 61 | +24 silly mapToRegistry using default registry | ||
| 62 | +25 silly mapToRegistry registry https://registry.npmjs.org/ | ||
| 63 | +26 silly mapToRegistry data Result { | ||
| 64 | +26 silly mapToRegistry raw: 'klas-file-downloader', | ||
| 65 | +26 silly mapToRegistry scope: null, | ||
| 66 | +26 silly mapToRegistry escapedName: 'klas-file-downloader', | ||
| 67 | +26 silly mapToRegistry name: 'klas-file-downloader', | ||
| 68 | +26 silly mapToRegistry rawSpec: '', | ||
| 69 | +26 silly mapToRegistry spec: 'latest', | ||
| 70 | +26 silly mapToRegistry type: 'tag' } | ||
| 71 | +27 silly mapToRegistry uri https://registry.npmjs.org/klas-file-downloader | ||
| 72 | +28 verbose publish registryBase https://registry.npmjs.org/ | ||
| 73 | +29 silly publish uploading /Users/junyoung/.npm/klas-file-downloader/0.0.3/package.tgz | ||
| 74 | +30 verbose request uri https://registry.npmjs.org/klas-file-downloader | ||
| 75 | +31 verbose request sending authorization for write operation | ||
| 76 | +32 info attempt registry request try #1 at 8:57:26 PM | ||
| 77 | +33 verbose request using bearer token for auth | ||
| 78 | +34 verbose request id d6c4649ba2332349 | ||
| 79 | +35 http request PUT https://registry.npmjs.org/klas-file-downloader | ||
| 80 | +36 http 403 https://registry.npmjs.org/klas-file-downloader | ||
| 81 | +37 verbose headers { 'content-type': 'application/json', | ||
| 82 | +37 verbose headers 'cache-control': 'max-age=300', | ||
| 83 | +37 verbose headers 'content-length': '95', | ||
| 84 | +37 verbose headers 'accept-ranges': 'bytes', | ||
| 85 | +37 verbose headers date: 'Tue, 09 May 2017 11:57:26 GMT', | ||
| 86 | +37 verbose headers via: '1.1 varnish', | ||
| 87 | +37 verbose headers connection: 'keep-alive', | ||
| 88 | +37 verbose headers 'x-served-by': 'cache-nrt6129-NRT', | ||
| 89 | +37 verbose headers 'x-cache': 'MISS', | ||
| 90 | +37 verbose headers 'x-cache-hits': '0', | ||
| 91 | +37 verbose headers 'x-timer': 'S1494331047.662517,VS0,VE285', | ||
| 92 | +37 verbose headers vary: 'Accept-Encoding' } | ||
| 93 | +38 verbose request invalidating /Users/junyoung/.npm/registry.npmjs.org/klas-file-downloader on PUT | ||
| 94 | +39 error publish Failed PUT 403 | ||
| 95 | +40 verbose stack Error: "You cannot publish over the previously published version 0.0.3." : klas-file-downloader | ||
| 96 | +40 verbose stack at makeError (/usr/local/lib/node_modules/npm/node_modules/npm-registry-client/lib/request.js:302:12) | ||
| 97 | +40 verbose stack at CachingRegistryClient.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/npm-registry-client/lib/request.js:290:14) | ||
| 98 | +40 verbose stack at Request._callback (/usr/local/lib/node_modules/npm/node_modules/npm-registry-client/lib/request.js:210:14) | ||
| 99 | +40 verbose stack at Request.self.callback (/usr/local/lib/node_modules/npm/node_modules/request/request.js:187:22) | ||
| 100 | +40 verbose stack at emitTwo (events.js:106:13) | ||
| 101 | +40 verbose stack at Request.emit (events.js:191:7) | ||
| 102 | +40 verbose stack at Request.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/request/request.js:1048:10) | ||
| 103 | +40 verbose stack at emitOne (events.js:96:13) | ||
| 104 | +40 verbose stack at Request.emit (events.js:188:7) | ||
| 105 | +40 verbose stack at IncomingMessage.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/request/request.js:969:12) | ||
| 106 | +41 verbose statusCode 403 | ||
| 107 | +42 verbose pkgid klas-file-downloader | ||
| 108 | +43 verbose cwd /Users/junyoung/Library/Mobile Documents/com~apple~CloudDocs/Junyoung/Opensource/klas-file-downloader | ||
| 109 | +44 error Darwin 16.5.0 | ||
| 110 | +45 error argv "/usr/local/Cellar/node/7.3.0/bin/node" "/usr/local/bin/npm" "publish" | ||
| 111 | +46 error node v7.3.0 | ||
| 112 | +47 error npm v3.10.10 | ||
| 113 | +48 error code E403 | ||
| 114 | +49 error "You cannot publish over the previously published version 0.0.3." : klas-file-downloader | ||
| 115 | +50 error If you need help, you may report this error at: | ||
| 116 | +50 error <https://github.com/npm/npm/issues> | ||
| 117 | +51 verbose exit [ 1, true ] |
| 1 | { | 1 | { |
| 2 | "name": "klas-file-downloader", | 2 | "name": "klas-file-downloader", |
| 3 | - "version": "0.0.1", | 3 | + "version": "0.0.3", |
| 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": { | ... | ... |
-
Please register or login to post a comment