This commit is contained in:
daniel-j 2016-08-22 21:57:19 +02:00
parent 8ba203b437
commit d1d78bc777
3 changed files with 158 additions and 126 deletions

View file

@ -1,6 +1,6 @@
#epubDialogContainer .drop-down-pop-up-container {
position: fixed;
position: absolute;
top: 0;
left: 0;
z-index: 1001;
@ -11,3 +11,11 @@
#epubDialogContainer .drop-down-pop-up-container .drop-down-pop-up h1 {
cursor: move;
}
#epubDialogContainer table.properties {
}
#epubDialogContainer table.properties td.label {
white-space: nowrap;
}

View file

@ -80,67 +80,58 @@ module.exports = class FimFic2Epub {
this.storyId = FimFic2Epub.getStoryId(storyId)
this.hasDownloaded = false
this.isDownloading = false
this.zip = null
this.downloadPromise = null
this.storyInfo = null
this.titlePage = null
this.chapterContent = []
this.remoteResources = new Map()
this.storyInfo = null
this.isDownloading = false
this.cachedFile = null
this.hasCoverImage = false
this.coverImageDimensions = {width: 0, height: 0}
this.includeTitlePage = true
this.categories = []
this.tags = []
this.zip = new JSZip()
}
download () {
return new Promise((resolve, reject) => {
if (this.isDownloading) {
reject('Already downloading')
return
}
if (this.hasDownloaded) {
resolve()
return
}
this.build().then(resolve).catch(reject)
})
}
if (this.downloadPromise) {
return this.downloadPromise
}
build () {
return new Promise((resolve, reject) => {
this.isDownloading = true
console.log('Fetching story metadata...')
this.zip = new JSZip()
this.zip.file('mimetype', 'application/epub+zip')
this.zip.file('META-INF/container.xml', containerXml)
console.log('Fetching story metadata...')
FimFic2Epub.fetchStoryInfo(this.storyId).then((storyInfo) => {
let p = FimFic2Epub.fetchStoryInfo(this.storyId)
.then((storyInfo) => {
this.storyInfo = storyInfo
this.storyInfo.uuid = 'urn:fimfiction:' + this.storyInfo.id
this.filename = FimFic2Epub.getFilename(this.storyInfo)
})
.then(this.fetchTitlePage.bind(this))
.then(() => {
this.downloadPromise = null
})
this.zip.file('OEBPS/Styles/style.css', styleCss)
this.zip.file('OEBPS/Styles/coverstyle.css', coverstyleCss)
if (this.includeTitlePage) {
this.zip.file('OEBPS/Styles/titlestyle.css', titlestyleCss)
}
this.zip.file('OEBPS/toc.ncx', template.createNcx(this))
this.fetchTitlePage(resolve, reject)
}).catch(reject)
})
this.downloadPromise = p
return p
}
fetchTitlePage (resolve, reject) {
build () {
return this.extractTitlePageInfo(this.titlePage)
.then(this.checkCoverImage.bind(this))
}
fetchTitlePage () {
console.log('Fetching index page...')
fetchRemote(this.storyInfo.url, (raw, type) => {
this.extractTitlePageInfo(raw).then(() => this.checkCoverImage(resolve, reject))
return new Promise((resolve, reject) => {
fetchRemote(this.storyInfo.url, (raw, type) => {
this.titlePage = raw
resolve(raw)
})
})
}
@ -219,45 +210,48 @@ module.exports = class FimFic2Epub {
})
}
checkCoverImage (resolve, reject) {
this.hasCoverImage = !!this.storyInfo.full_image
checkCoverImage () {
return new Promise((resolve, reject) => {
this.hasCoverImage = !!this.storyInfo.full_image
if (this.hasCoverImage) {
this.remoteResources.set(this.storyInfo.full_image, {filename: 'cover', where: ['cover']})
if (this.hasCoverImage) {
this.remoteResources.set(this.storyInfo.full_image, {filename: 'cover', where: ['cover']})
if (!isNode) {
let coverImage = new Image()
coverImage.src = this.storyInfo.full_image
if (!isNode) {
let coverImage = new Image()
coverImage.src = this.storyInfo.full_image
coverImage.addEventListener('load', () => {
this.coverImageDimensions.width = coverImage.width
this.coverImageDimensions.height = coverImage.height
coverImage.addEventListener('load', () => {
this.coverImageDimensions.width = coverImage.width
this.coverImageDimensions.height = coverImage.height
this.processStory(resolve, reject)
}, false)
coverImage.addEventListener('error', () => {
console.warn('Unable to fetch cover image, skipping...')
this.hasCoverImage = false
this.processStory(resolve, reject)
})
} else {
this.processStory(resolve, reject)
}, false)
coverImage.addEventListener('error', () => {
console.warn('Unable to fetch cover image, skipping...')
this.hasCoverImage = false
this.processStory(resolve, reject)
})
}
} else {
this.processStory(resolve, reject)
}
} else {
this.processStory(resolve, reject)
}
})
}
processStory (resolve, reject) {
console.log('Fetching chapters...')
this.fetchChapters(() => {
this.zip.file('OEBPS/Text/nav.xhtml', template.createNav(this))
this.fetchChapters().then(() => {
console.log('Fetching remote files...')
this.fetchRemoteFiles(() => {
console.log('Finishing build...')
this.zip.file('mimetype', 'application/epub+zip')
this.zip.file('META-INF/container.xml', containerXml)
let coverFilename = ''
this.remoteResources.forEach((r, url) => {
let dest = '../' + r.dest
@ -287,6 +281,8 @@ module.exports = class FimFic2Epub {
this.chapterContent.length = 0
this.zip.file('OEBPS/content.opf', template.createOpf(this))
if (this.hasCoverImage) {
this.zip.file('OEBPS/Text/cover.xhtml', template.createCoverPage(coverFilename, this.coverImageDimensions.width, this.coverImageDimensions.height))
} else {
@ -297,9 +293,15 @@ module.exports = class FimFic2Epub {
this.zip.file('OEBPS/Text/title.xhtml', template.createTitlePage(this))
}
this.zip.file('OEBPS/content.opf', template.createOpf(this))
this.zip.file('OEBPS/Text/nav.xhtml', template.createNav(this))
this.zip.file('OEBPS/toc.ncx', template.createNcx(this))
this.zip.file('OEBPS/Styles/style.css', styleCss)
this.zip.file('OEBPS/Styles/coverstyle.css', coverstyleCss)
if (this.includeTitlePage) {
this.zip.file('OEBPS/Styles/titlestyle.css', titlestyleCss)
}
this.isDownloading = false
this.hasDownloaded = true
resolve()
})
@ -353,44 +355,46 @@ module.exports = class FimFic2Epub {
recursive()
}
fetchChapters (cb) {
let chapters = this.storyInfo.chapters
let chapterCount = this.storyInfo.chapters.length
let currentChapter = 0
let completeCount = 0
fetchChapters () {
return new Promise((resolve, reject) => {
let chapters = this.storyInfo.chapters
let chapterCount = this.storyInfo.chapters.length
let currentChapter = 0
let completeCount = 0
if (chapterCount === 0) {
cb()
return
}
let recursive = () => {
let index = currentChapter++
let ch = chapters[index]
if (!ch) {
if (chapterCount === 0) {
resolve()
return
}
console.log('Fetching chapter ' + (index + 1) + ' of ' + chapters.length + ': ' + ch.title)
let url = ch.link.replace('http', 'https')
fetchRemote(url, (html) => {
template.createChapter(ch, html, (html) => {
this.findRemoteResources('ch_' + zeroFill(3, index + 1), index, html)
this.chapterContent[index] = html
completeCount++
if (completeCount < chapterCount) {
recursive()
} else {
cb()
}
})
})
}
// concurrent downloads!
recursive()
recursive()
recursive()
recursive()
let recursive = () => {
let index = currentChapter++
let ch = chapters[index]
if (!ch) {
return
}
console.log('Fetching chapter ' + (index + 1) + ' of ' + chapters.length + ': ' + ch.title)
let url = ch.link.replace('http', 'https')
fetchRemote(url, (html) => {
template.createChapter(ch, html, (html) => {
this.findRemoteResources('ch_' + zeroFill(3, index + 1), index, html)
this.chapterContent[index] = html
completeCount++
if (completeCount < chapterCount) {
recursive()
} else {
resolve()
}
})
})
}
// concurrent downloads!
recursive()
recursive()
recursive()
recursive()
})
}
findRemoteResources (prefix, where, html) {

View file

@ -36,22 +36,20 @@ let checkbox = {
let dialog = {
controller (args) {
this.dragging = m.prop(false)
this.xpos = m.prop(100)
this.ypos = m.prop(100)
this.xpos = m.prop(0)
this.ypos = m.prop(0)
this.el = m.prop(null)
this.progress = m.prop(0)
this.ondown = (e) => {
let el = this.el().firstChild
let rect = el.getBoundingClientRect()
let offset = {x: e.pageX - rect.left, y: e.pageY - rect.top}
let rect = this.el().firstChild.getBoundingClientRect()
let offset = {x: e.pageX - rect.left - document.body.scrollLeft, y: e.pageY - rect.top - document.body.scrollTop}
this.dragging(true)
let onmove = (e) => {
e.preventDefault()
if (this.dragging()) {
let rect = el.getBoundingClientRect()
this.xpos(Math.max(0, Math.min(e.pageX - offset.x, window.innerWidth - rect.width)))
this.ypos(Math.max(0, Math.min(e.pageY - offset.y, window.innerHeight - rect.height)))
// console.log(e.pageX, e.pageY)
m.redraw()
this.xpos(Math.max(0, e.pageX - offset.x))
this.ypos(Math.max(0, e.pageY - offset.y))
this.move()
}
}
let onup = () => {
@ -62,12 +60,48 @@ let dialog = {
window.addEventListener('mousemove', onmove, false)
window.addEventListener('mouseup', onup, false)
}
this.onOpen = function (el, first) {
if (!first) {
this.el(el)
let rect = this.el().firstChild.getBoundingClientRect()
this.xpos((window.innerWidth / 2) - (rect.width / 2) + document.body.scrollLeft)
this.ypos((window.innerHeight / 2) - (rect.height / 2) + document.body.scrollTop)
this.move()
}
}
this.move = () => {
this.el().style.left = this.xpos() + 'px'
this.el().style.top = this.ypos() + 'px'
}
this.createEpub = (e) => {
e.target.disabled = true
ffc.download()
.then(ffc.build.bind(ffc))
.then(ffc.getFile.bind(ffc)).then((file) => {
console.log('Saving file...')
if (typeof safari !== 'undefined') {
blobToDataURL(file, (dataurl) => {
document.location.href = dataurl
alert('Add .epub to the filename of the downloaded file')
})
} else {
saveAs(file, ffc.filename)
}
})
}
},
view (ctrl, args, extras) {
return m('.drop-down-pop-up-container', {config: ctrl.el, style: {left: ctrl.xpos() + 'px', top: ctrl.ypos() + 'px'}}, m('.drop-down-pop-up', [
m('h1', {onmousedown: ctrl.ondown}, m('i.fa.fa-book'), 'Export EPUB', m('a.close_button', {onclick: closeDialog})),
return m('.drop-down-pop-up-container', {config: ctrl.onOpen.bind(ctrl)}, m('.drop-down-pop-up', [
m('h1', {onmousedown: ctrl.ondown}, m('i.fa.fa-book'), 'Export to EPUB', m('a.close_button', {onclick: closeDialog})),
m('.drop-down-pop-up-content', [
m(checkbox, {name: 'toggle-chapter-headings'}, 'Toggle chapter headings')
m('table.properties', [
m('tr', m('td.label', 'Cover image'), m('td', 'some config')),
m('tr', m('td.label', 'Chapter headings'), m('td', m(checkbox, {name: 'toggle-chapter-headings'})))
]),
m('.drop-down-pop-up-footer', [
m('button.styled_button', {onclick: ctrl.createEpub}, 'Create EPUB'),
ctrl.progress() > 0 ? m('.rating_container', m('.bars_container', m('.bar_container', m('.bar_dislike', m('.bar.bar_like', {style: {width: ctrl.progress() * 100 + '%'}}))))) : null
])
])
]))
}
@ -85,20 +119,6 @@ function clickButton () {
if (!ffc) ffc = new FimFic2Epub(STORY_ID)
openDialog()
return
ffc.download().then(ffc.getFile.bind(ffc)).then((file) => {
console.log('Saving file...')
if (typeof safari !== 'undefined') {
blobToDataURL(file, (dataurl) => {
document.location.href = dataurl
alert('Add .epub to the filename of the downloaded file')
})
} else {
saveAs(file, ffc.filename)
}
})
}
if (epubButton) {