mirror of
https://github.com/daniel-j/fimfic2epub.git
synced 2024-05-13 08:52:56 +12:00
added Safari extension support
This commit is contained in:
parent
9aa9c1e1a1
commit
0ad2d0c82a
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,5 +1,8 @@
|
|||
.DS_Store
|
||||
node_modules/
|
||||
extension/fimfic2epub.js
|
||||
extension/eventPage.js
|
||||
extension.crx
|
||||
extension.pem
|
||||
extension.xpi
|
||||
fimfic2epub.safariextension/
|
||||
|
|
56
extension/Info.plist
Normal file
56
extension/Info.plist
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Author</key>
|
||||
<string>djazz</string>
|
||||
<key>Builder Version</key>
|
||||
<string>11601.5.17.1</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>fimfic2epub</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.yourcompany.fimfic2epub</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>Chrome</key>
|
||||
<dict>
|
||||
<key>Global Page</key>
|
||||
<string>global.html</string>
|
||||
</dict>
|
||||
<key>Content</key>
|
||||
<dict>
|
||||
<key>Scripts</key>
|
||||
<dict>
|
||||
<key>End</key>
|
||||
<array>
|
||||
<string>fimfic2epub.js</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>Whitelist</key>
|
||||
<array>
|
||||
<string>http://www.fimfiction.net/story/*</string>
|
||||
<string>https://www.fimfiction.net/story/*</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>DeveloperIdentifier</key>
|
||||
<string>0000000000</string>
|
||||
<key>ExtensionInfoDictionaryVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>Permissions</key>
|
||||
<dict>
|
||||
<key>Website Access</key>
|
||||
<dict>
|
||||
<key>Include Secure Pages</key>
|
||||
<true/>
|
||||
<key>Level</key>
|
||||
<string>All</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>Website</key>
|
||||
<string>https://github.com/daniel-j/fimfic2epub</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,29 +0,0 @@
|
|||
/* global chrome */
|
||||
'use strict'
|
||||
|
||||
function fetch (url, cb, type) {
|
||||
if (url.indexOf('//') === 0) {
|
||||
url = 'http:' + url
|
||||
}
|
||||
let x = new XMLHttpRequest()
|
||||
x.open('get', url, true)
|
||||
if (type) {
|
||||
x.responseType = type
|
||||
}
|
||||
x.onload = function () {
|
||||
console.log(x.getResponseHeader('content-type'))
|
||||
cb(URL.createObjectURL(x.response), x.getResponseHeader('content-type'))
|
||||
}
|
||||
x.onerror = function () {
|
||||
console.error('error')
|
||||
cb(null)
|
||||
}
|
||||
x.send()
|
||||
}
|
||||
|
||||
let onMessage = chrome.extension.onMessage ? chrome.extension.onMessage : chrome.runtime.onMessage
|
||||
|
||||
onMessage.addListener(function (request, sender, sendResponse) {
|
||||
fetch(request, sendResponse, 'blob')
|
||||
return true
|
||||
})
|
10
extension/global.html
Normal file
10
extension/global.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Background page</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript" src="eventPage.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -67,12 +67,11 @@ function webpackTask (callback) {
|
|||
}
|
||||
|
||||
let lintPipe = lazypipe()
|
||||
.pipe(filter, ['**/*', '!extension/fimfic2epub.js'])
|
||||
.pipe(standard)
|
||||
.pipe(standard.reporter, 'default', { breakOnError: false })
|
||||
|
||||
// Cleanup task
|
||||
gulp.task('clean', () => del('extension/fimfic2epub.js'))
|
||||
gulp.task('clean', () => del(['extension/fimfic2epub.js', 'extension/eventPage.js']))
|
||||
|
||||
// Main tasks
|
||||
gulp.task('webpack', webpackTask)
|
||||
|
@ -83,7 +82,7 @@ gulp.task('watch:webpack', () => {
|
|||
})
|
||||
|
||||
gulp.task('lint', () => {
|
||||
return gulp.src(['gulpfile.babel.js', 'webpack.config.babel.js', 'src/**/*.js', 'extension/**/*.js']).pipe(lintPipe())
|
||||
return gulp.src(['gulpfile.babel.js', 'webpack.config.babel.js', 'src/**/*.js']).pipe(lintPipe())
|
||||
})
|
||||
gulp.task('watch:lint', () => {
|
||||
return watch(['src/**/*.js'], watchOpts, function (file) {
|
||||
|
|
44
src/eventPage.js
Normal file
44
src/eventPage.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* global chrome, safari */
|
||||
'use strict'
|
||||
|
||||
function fetch (url, cb, type) {
|
||||
if (url.indexOf('//') === 0) {
|
||||
url = 'http:' + url
|
||||
}
|
||||
let x = new XMLHttpRequest()
|
||||
x.open('get', url, true)
|
||||
if (type) {
|
||||
x.responseType = type
|
||||
}
|
||||
x.onload = function () {
|
||||
cb(x.response, x.getResponseHeader('content-type'))
|
||||
}
|
||||
x.onerror = function () {
|
||||
console.error('error')
|
||||
cb(null)
|
||||
}
|
||||
x.send()
|
||||
}
|
||||
|
||||
if (typeof safari !== 'undefined') {
|
||||
safari.application.addEventListener('message', function (ev) {
|
||||
let url = ev.message
|
||||
fetch(url, function (buffer, type) {
|
||||
console.log('Fetched ' + url + ' (' + type + ')')
|
||||
ev.target.page.dispatchMessage('remote', {
|
||||
input: url,
|
||||
output: buffer,
|
||||
type: type
|
||||
})
|
||||
}, 'arraybuffer')
|
||||
}, false)
|
||||
} else {
|
||||
let onMessage = chrome.extension.onMessage ? chrome.extension.onMessage : chrome.runtime.onMessage
|
||||
|
||||
onMessage.addListener(function (request, sender, sendResponse) {
|
||||
fetch(request, function (blob, type) {
|
||||
sendResponse(URL.createObjectURL(blob), type)
|
||||
}, 'blob')
|
||||
return true
|
||||
})
|
||||
}
|
115
src/main.js
115
src/main.js
|
@ -1,4 +1,4 @@
|
|||
/* global chrome */
|
||||
/* global chrome, safari */
|
||||
'use strict'
|
||||
|
||||
import JSZip from 'jszip'
|
||||
|
@ -95,7 +95,7 @@ function fetchChapters (cb) {
|
|||
function recursive () {
|
||||
let ch = chapters[currentChapter]
|
||||
console.log('Fetching chapter ' + ch.id + ' ' + ch.title)
|
||||
fetch(ch.link.replace('http', 'https'), function (html) {
|
||||
fetchRemote(ch.link.replace('http', 'https'), function (html) {
|
||||
html = parseChapter(ch, html)
|
||||
chapterContent[ch.id] = html
|
||||
currentChapter++
|
||||
|
@ -109,7 +109,62 @@ function fetchChapters (cb) {
|
|||
recursive()
|
||||
}
|
||||
|
||||
function fetchRemote (zip, cb) {
|
||||
let safariQueue = {}
|
||||
|
||||
function safariHandler (ev) {
|
||||
let type = ev.message.type
|
||||
let url = ev.message.input
|
||||
let data = ev.message.output // arraybuffer
|
||||
if (!safariQueue[url]) {
|
||||
// console.error("Unable to get callback for " + url, JSON.stringify(safariQueue))
|
||||
return
|
||||
}
|
||||
let cb = safariQueue[url].cb
|
||||
let responseType = safariQueue[url].responseType
|
||||
console.log(url, cb, responseType, data)
|
||||
delete safariQueue[url]
|
||||
|
||||
if (responseType === 'blob') {
|
||||
let blob = new Blob([data], {type: type})
|
||||
cb(blob, type)
|
||||
} else {
|
||||
if (!responseType) {
|
||||
let blob = new Blob([data], {type: type})
|
||||
let fr = new FileReader()
|
||||
fr.onloadend = function () {
|
||||
cb(fr.result, type)
|
||||
}
|
||||
fr.readAsText(blob)
|
||||
/*
|
||||
let str = ''
|
||||
let arr = new Uint8Array(data)
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
str += String.fromCharCode(arr[i])
|
||||
}
|
||||
cb(str, type)
|
||||
*/
|
||||
} else {
|
||||
cb(data, type)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof safari !== 'undefined') {
|
||||
safari.self.addEventListener('message', safariHandler, false)
|
||||
}
|
||||
|
||||
function fetchRemote (url, cb, responseType) {
|
||||
if (typeof chrome !== 'undefined' && chrome.runtime.sendMessage) {
|
||||
chrome.runtime.sendMessage(url, function (objurl) {
|
||||
fetch(objurl, cb, responseType)
|
||||
URL.revokeObjectURL(objurl)
|
||||
})
|
||||
} else {
|
||||
safariQueue[url] = {cb: cb, responseType: responseType}
|
||||
safari.self.tab.dispatchMessage('remote', url)
|
||||
}
|
||||
}
|
||||
|
||||
function fetchRemoteFiles (zip, cb) {
|
||||
let iter = remoteResources.entries()
|
||||
let counter = 0
|
||||
|
||||
|
@ -122,26 +177,18 @@ function fetchRemote (zip, cb) {
|
|||
let url = r[0]
|
||||
r = r[1]
|
||||
console.log('Fetching remote file ' + r.filename, url)
|
||||
chrome.runtime.sendMessage(url, function (objUrl) {
|
||||
if (objUrl) {
|
||||
fetch(objUrl, function (data, type) {
|
||||
r.dest = null
|
||||
r.type = type
|
||||
let dest = mimeMap[type]
|
||||
fetchRemote(url, function (data, type) {
|
||||
r.dest = null
|
||||
r.type = type
|
||||
let dest = mimeMap[type]
|
||||
|
||||
if (dest) {
|
||||
r.dest = dest.replace('*', r.filename)
|
||||
zip.file(r.dest, data)
|
||||
}
|
||||
URL.revokeObjectURL(objUrl)
|
||||
counter++
|
||||
recursive()
|
||||
}, 'arraybuffer')
|
||||
} else {
|
||||
counter++
|
||||
recursive()
|
||||
if (dest) {
|
||||
r.dest = dest.replace('*', r.filename)
|
||||
zip.file(r.dest, data)
|
||||
}
|
||||
})
|
||||
counter++
|
||||
recursive()
|
||||
}, 'arraybuffer')
|
||||
}
|
||||
recursive()
|
||||
}
|
||||
|
@ -161,7 +208,7 @@ function downloadStory () {
|
|||
|
||||
console.log('Fetching story...')
|
||||
|
||||
fetch(apiUrl, function (raw) {
|
||||
fetchRemote(apiUrl, function (raw, type) {
|
||||
let data
|
||||
try {
|
||||
data = JSON.parse(raw)
|
||||
|
@ -185,7 +232,7 @@ function downloadStory () {
|
|||
zip.file('nav.xhtml', createNav())
|
||||
|
||||
fetchChapters(function () {
|
||||
fetchRemote(zip, function () {
|
||||
fetchRemoteFiles(zip, function () {
|
||||
remoteResources.forEach((r, url) => {
|
||||
if (r.chapter && r.originalUrl && r.dest) {
|
||||
chapterContent[r.chapter] = chapterContent[r.chapter].replace(
|
||||
|
@ -223,7 +270,7 @@ function downloadStory () {
|
|||
})
|
||||
*/
|
||||
|
||||
console.log('packing epub...')
|
||||
console.log('Packaging epub...')
|
||||
|
||||
zip
|
||||
.generateAsync({
|
||||
|
@ -243,8 +290,22 @@ function downloadStory () {
|
|||
})
|
||||
}
|
||||
|
||||
function blobToDataURL (blob, callback) {
|
||||
let a = new FileReader()
|
||||
a.onloadend = function (e) { callback(a.result) }
|
||||
a.readAsDataURL(blob)
|
||||
}
|
||||
|
||||
function saveStory () {
|
||||
saveAs(cachedBlob, storyInfo.title + ' by ' + storyInfo.author.name + '.epub')
|
||||
console.log('Saving epub...')
|
||||
if (typeof safari !== 'undefined') {
|
||||
blobToDataURL(cachedBlob, function (dataurl) {
|
||||
document.location.href = dataurl
|
||||
alert('Rename downloaded file to .epub')
|
||||
})
|
||||
} else {
|
||||
saveAs(cachedBlob, storyInfo.title + ' by ' + storyInfo.author.name + '.epub')
|
||||
}
|
||||
}
|
||||
|
||||
function parseChapter (ch, html) {
|
||||
|
@ -320,7 +381,7 @@ function parseChapter (ch, html) {
|
|||
}
|
||||
|
||||
function subjects (s) {
|
||||
var list = []
|
||||
let list = []
|
||||
for (let i = 0; i < s.length; i++) {
|
||||
list.push(m('dc:subject', s[i]))
|
||||
}
|
||||
|
@ -383,7 +444,7 @@ function createOpf () {
|
|||
}
|
||||
|
||||
function navPoints (list) {
|
||||
var arr = []
|
||||
let arr = []
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
list[i]
|
||||
arr.push(m('navPoint', {id: 'navPoint-' + (i + 1), playOrder: i + 1}, [
|
||||
|
|
|
@ -6,7 +6,8 @@ let inProduction = process.env.NODE_ENV === 'production' || process.argv.indexOf
|
|||
|
||||
export default {
|
||||
entry: {
|
||||
fimfic2epub: ['./src/main']
|
||||
fimfic2epub: ['./src/main'],
|
||||
eventPage: ['./src/eventPage']
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, '/'),
|
||||
|
|
Loading…
Reference in a new issue