Last active
August 31, 2021 09:07
-
-
Save yuru4c/846dbba5de27e370c0e233aba68ee3b6 to your computer and use it in GitHub Desktop.
HAR に含まれるファイルを展開(NW.js 用)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="ja"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>har reader</title> | |
<style type="text/css"> | |
body { | |
white-space: nowrap; | |
} | |
.browser .nw { | |
display: none; | |
} | |
</style> | |
</head> | |
<body class="browser"> | |
<form name="form"> | |
<fieldset name="fieldset"> | |
<p> | |
<label> | |
入力: | |
<input type="file" accept=".har" multiple name="file"> | |
</label> | |
<input type="button" name="show" value="表示"> | |
</p> | |
<p class="nw"> | |
<label> | |
出力: | |
<input type="file" name="directory" nwdirectory> | |
</label> | |
<input type="button" name="save" value="保存"> | |
</p> | |
</fieldset> | |
</form> | |
<div id="list"></div> | |
<script type="text/javascript" src="script.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "har-reader", | |
"version": "0.0.0.4", | |
"main": "index.html" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function () { | |
var nw = this.nw; | |
var path; | |
var fs; | |
if (nw != null) { | |
path = require('path'); | |
fs = require('fs'); | |
} | |
var RE = { | |
FILE: /[^/]*$/, DOT: /\.|$/, DIR: /\/$/, | |
REPLACE: /\\|\/|:|\*|\?|"|<|>|\||\.|~/g | |
}; | |
function decode(base64) { | |
var bin = atob(base64); | |
var array = new Uint8Array(bin.length); | |
for (var i = 0; i < array.length; i++) { | |
array[i] = bin.charCodeAt(i); | |
} | |
return array.buffer; | |
} | |
function createBlob(data, type) { | |
var blob = new Blob([data], {type: type}); | |
return URL.createObjectURL(blob); | |
} | |
function createHref(content) { | |
var encoding = content['encoding']; | |
var mimeType = content['mimeType']; | |
var text = content['text']; | |
if (text == null) { | |
return null; | |
} | |
if (!encoding) { | |
return createBlob(text, mimeType); | |
} | |
switch (encoding) { | |
case 'base64': | |
return createBlob(decode(text), mimeType); | |
} | |
return 'data:' + mimeType + ';' + encoding + ',' + text; | |
} | |
function createFilename(url, headers, replace) { | |
var filename = url.pathname.match(RE.FILE)[0] || '#'; | |
var lastModified; | |
for (var i = 0; i < headers.length; i++) { | |
var header = headers[i]; | |
if (header['name'].toLowerCase() == 'last-modified') { | |
lastModified = header['value']; | |
break; | |
} | |
} | |
if (lastModified == null) { | |
return filename; | |
} | |
if (replace) { | |
lastModified = lastModified.replace(RE.REPLACE, '_'); | |
} | |
return filename.replace(RE.DOT, ' (' + lastModified + ')$&'); | |
} | |
function createDirname(destination, url) { | |
var pathname = url.pathname; | |
var dir = RE.DIR.test(pathname) ? | |
pathname : | |
path.dirname(pathname); | |
return path.join(destination, url.hostname, dir); | |
} | |
function Show(list) { | |
this.fragment = document.createDocumentFragment(); | |
this.ol = document.createElement('ol'); | |
list.innerHTML = ''; | |
list.appendChild(this.ol); | |
} | |
Show.prototype.each = function (request, response) { | |
var content = response['content']; | |
var href = createHref(content); | |
if (href == null) return; | |
var url = request['url']; | |
var headers = response['headers']; | |
var li = document.createElement('li'); | |
var a = document.createElement('a'); | |
a.href = href; | |
a.download = createFilename(new URL(url), headers, false); | |
a.appendChild(document.createTextNode(url)); | |
li.appendChild(a); | |
this.fragment.appendChild(li); | |
}; | |
Show.prototype.done = function () { | |
this.ol.appendChild(this.fragment); | |
}; | |
function Save(destination) { | |
this.destination = destination; | |
} | |
Save.prototype.each = function (request, response) { | |
var content = response['content']; | |
var text = content['text']; | |
if (text == null) return; | |
var url = request['url']; | |
var headers = response['headers']; | |
var encoding = content['encoding']; | |
var urlObj = new URL(url); | |
var dir = createDirname(this.destination, urlObj); | |
var file = path.format({ | |
dir: dir, | |
base: createFilename(urlObj, headers, true) | |
}); | |
fs.mkdirSync(dir, {recursive: true}); | |
try { | |
fs.writeFileSync(file, text, {encoding: encoding, flag: 'wx'}); | |
} catch (e) { | |
switch (e.errno) { | |
case -4075: break; | |
default: throw e; | |
} | |
} | |
}; | |
Save.prototype.done = function () { }; | |
function Context(elements) { | |
this.fieldset = elements['fieldset']; | |
this.input = elements['file']; | |
this.title = document.title; | |
this.verb = null; | |
} | |
function Loop(context, action) { | |
context.fieldset.disabled = true; | |
this.context = context; | |
this.action = action; | |
this.files = context.input.files; | |
this.length = this.files.length; | |
this.index = -1; | |
this.file = null; | |
this.next(); | |
} | |
Loop.prototype.each = function (entry) { | |
var request = entry['request']; | |
if (request['method'] != 'GET') return; | |
var response = entry['response']; | |
if (response['status'] >= 400) return; | |
this.action.each(request, response); | |
}; | |
Loop.prototype.next = function () { | |
this.index++; | |
if (this.index < this.length) { | |
this.file = this.files[this.index]; | |
document.title = ( | |
'[' + (this.index + '/' + this.length) + '] ' + | |
this.context.verb + '... - ' + this.context.title | |
); | |
fileReader.readAsText(this.file); | |
} else { | |
this.action.done(); | |
document.title = this.context.title; | |
this.context.fieldset.disabled = false; | |
} | |
}; | |
var loop; | |
var fileReader = new FileReader(); | |
fileReader.onerror = function () { | |
console.warn({ | |
file: loop.file, | |
error: this.error | |
}); | |
loop.next(); | |
}; | |
fileReader.onload = function () { | |
try { | |
var json = JSON.parse(this.result); | |
var entries = json['log']['entries']; | |
for (var i = 0; i < entries.length; i++) { | |
try { | |
loop.each(entries[i]); | |
} catch (error) { | |
console.warn({ | |
file: loop.file, | |
index: i, | |
error: error | |
}); | |
} | |
} | |
} catch (error) { | |
console.warn({ | |
file: loop.file, | |
error: error | |
}); | |
} | |
loop.next(); | |
}; | |
window.onload = function () { | |
var list = document.getElementById('list'); | |
var elements = document.forms['form'].elements; | |
var context = new Context(elements); | |
elements['show'].onclick = function () { | |
context.verb = this.value; | |
loop = new Loop(context, new Show(list)); | |
}; | |
if (nw != null) { | |
var directory = elements['directory']; | |
elements['save'].onclick = function () { | |
var destination = directory.value; | |
if (destination) { | |
context.verb = this.value; | |
loop = new Loop(context, new Save(destination)); | |
} | |
}; | |
document.body.className = ''; | |
} | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment