UNPKG

6.93 kBtext/coffeescriptView Raw
1#!/usr/bin/env node_modules/coffee-script/bin/coffee
2
3fs = require('fs')
4request = require('request')
5program = require('commander')
6async = require('async')
7_ = require('lodash')
8exec = require('child_process').exec
9moment = require('moment')
10cheerio = require('cheerio')
11clc = require('cli-color')
12mangaUrls = require('./manga')
13
14program
15 .version('0.0.1')
16 .usage('-m [manga ex. bleach] -v [volume ex. 30] -e [episode ex. 268]')
17 .option('-m, --manga <value>', 'Specify manga, view manga list on https://github.com/phatograph/mangafetcher#currently-supported-manga')
18 .option('-v, --volume <n>', 'Specify volume')
19 .option('-e, --episode <a>..<b>', 'Specify episode', (val) -> val.split('..').map(Number))
20 .option('-p, --pages [items]', 'Specify pages (optional) e.g. -p 2,4,5', (val) -> val.split(','))
21 .option('-l, --list', 'List mode')
22 .option('-x, --eplist', 'Episode List mode')
23 .parse(process.argv)
24
25##############################################################################
26# Manga Urls
27##############################################################################
28
29
30##############################################################################
31# Image Downloading Functions
32##############################################################################
33
34padding = (value, length) ->
35 String(('0' for i in [0...length]).join('') + value).slice(length * -1)
36
37createFolder = (folderPath) ->
38 for path in folderPath.split '/'
39 initPath = "#{initPath || '.'}/#{path}"
40 fs.mkdirSync(initPath) unless fs.existsSync(initPath)
41
42mangaDownload = (vol, ep) ->
43 fraction = if ep.match /\./ then _.last(ep.split('.')) else false
44 ep = ep.split('.')[0]
45
46 uri = switch program.manga
47 when 'bleach', 'one-piece', 'naruto', 'yugi'
48 "#{mangaUrls[program.manga]}/v#{if vol is 'TBD' then 'TBD' else padding(vol, 2)}/c#{padding(ep, 3)}/"
49 when 'sk'
50 "#{mangaUrls[program.manga]}/v#{vol}/c#{ep}"
51 when 'gundam-origin', 'mahoromatic-2', 'tsubasa'
52 "#{mangaUrls[program.manga]}/v#{padding(vol, 2)}/c#{padding(ep, 3)}#{if fraction then '.' + fraction else ''}"
53 else "#{mangaUrls[program.manga]}/c#{padding(ep, 3)}#{if fraction then '.' + fraction else ''}"
54
55 console.log uri
56
57 request uri: uri, (err, res, body) ->
58 if err or res.statusCode isnt 200
59 console.log clc.red "Oops, something went wrong #{'(Error: ' + res.statusCode + ')'if res}"
60 return false
61
62 $ = cheerio.load(body)
63 pageAmount = switch program.manga
64 when 'bleach', 'one-piece', 'naruto' # for mangafoxes
65 $('form#top_bar select.m option').length
66 else $('section.readpage_top select.wid60 option').length
67 pages = program.pages || [0..pageAmount]
68 uri = uri.slice(0, -1) if uri.match /\/$/ # Remove trailing `/`
69
70 console.log clc.green "Downloading up to #{pages.length} page(s)"
71 for i in _.clone pages
72 do (i) ->
73 request uri: "#{uri}/#{i}.html", followRedirect: false, (err, res, body) ->
74 $$ = cheerio.load(body)
75 paddedVol = padding(vol, 3)
76 paddedEp = padding(ep, 3)
77 paddedEp += ".#{fraction}" if fraction
78
79 if err or res.statusCode isnt 200
80 pages.splice(pages.indexOf(i), 1)
81 else
82 img = $$('img#image')
83
84 unless img.length
85 pages.splice(pages.indexOf(i), 1)
86 else
87 imgUri = switch program.manga
88 when 'bleach', 'one-piece', 'naruto'
89 img.attr('onerror').match(/http.+jpg/)[0] # New manga seems to fallback to another CDN
90 else img.attr('src')
91
92 request.head uri: imgUri, followRedirect: false, (err2, res2, body2) ->
93 if res2.headers['content-type'] is 'image/jpeg'
94 folderPath = "manga/#{program.manga}/#{program.manga}-#{paddedVol}-#{paddedEp}"
95 fileName = "#{padding(i, 3)}.jpg"
96 filePath = "./#{folderPath}/#{fileName}"
97
98 createFolder(folderPath)
99 request(uri: imgUri, timeout: 120 * 1000)
100 .pipe fs.createWriteStream(filePath)
101 .on 'finish', ->
102 pages.splice(pages.indexOf(i), 1)
103
104 # Since iOS seems to sort images by created date, this should do the trick.
105 # Also rounds this by 60 (minutes)
106 exec("touch -t #{moment().format('YYYYMMDD')}#{padding(~~(i / 60), 2)}#{padding(i % 60, 2)} #{filePath}")
107
108 if pages.length is 0
109 console.log clc.green "\nDone ##{ep}!"
110 else if pages.length > 3
111 if (pageAmount - pages.length) % 5
112 process.stdout.write "."
113 else
114 process.stdout.write "#{pageAmount - pages.length}"
115 else
116 process.stdout.write "\nRemaining (##{ep}): #{pages.join(', ')}" if pages.length
117
118mangaList = ->
119 for name, url of mangaUrls
120 do (name, url) ->
121 request uri: "#{mangaUrls[name]}/", followRedirect: false, (err, res, body) ->
122 $ = cheerio.load(body)
123 label = switch name
124 when 'bleach', 'one-piece', 'naruto'
125 $('a.tips').first().text().trim()
126 else $('div.detail_list span.left a.color_0077').first().text().trim()
127 labelNum = ~~(_.last(label.split(' ')))
128 folderPath = "./manga/#{name}"
129
130 if fs.existsSync(folderPath)
131 fs.readdir folderPath, (e, folders) ->
132 _.remove(folders, (x) -> x is '.DS_Store')
133 latestFolder = ~~(_.last(_.last(folders).split('-'))) if folders.length
134 color = if latestFolder is labelNum then clc.green else clc.red
135
136 console.log "#{label} [#{clc.yellow name}] (local: #{color(latestFolder || '-')}/#{labelNum})"
137
138episodeList = ->
139 unless program.manga
140 console.log 'Error: please specify manga'
141 return
142
143 request uri: "#{mangaUrls[program.manga]}/", followRedirect: false, (err, res, body) ->
144 $ = cheerio.load(body)
145 $('div.detail_list ul span.left').each (i, l) ->
146 text = @parent().text().trim()
147 .replace(/\r?\n|\r|\t/g, '')
148 .replace(/\s{2,}/g, ' | ')
149 console.log text
150
151##############################################################################
152# App Kickoff!
153##############################################################################
154
155if program.list then mangaList()
156else if program.eplist then episodeList()
157else if program.manga and program.episode
158 episodes = [program.episode[0]..(program.episode[1] || program.episode[0])]
159 for ep in episodes
160 mangaDownload(program.volume || 0, ep.toString())
161else
162 console.log 'Error: please specify manga, volume and episode'