pixiv / pixiv-novel-parser Goto Github PK
View Code? Open in Web Editor NEWpixiv-novel-parser
License: Mozilla Public License 2.0
pixiv-novel-parser
License: Mozilla Public License 2.0
node.jsだけでなく、Web browser上でtestする。
package.json, bower.json, component.json を編集する。git tagを打つ。
APIと抽象構文木のdocumentを軽く書きませう。軽く。
現在node.jsでしか動作しませんが、Web browserでも動作する様にbuildします。
普段はuupaa module pattern + UglifyJSを使ってゐますが、Componentの使用を検討してゐます。
取り敢へずPublic Domainにしてますが、取り敢へずCC0にしておきます。
現行の novel_parser.js も読もう(;∩;)
// http://source.pixiv.net/www/js/novel_parser.js
var cur_page = 1;
var max_page = 1;
var temp_page = 1;
var illust_id_list = [];
var temp_illust_id_list = [];
var illust_html_list = [];
var temp_chapter_list = [];
var chapter_list = [];
var RPC_NOVEL_ILLUST_URL = "/novel/rpc_novel_illust.php";
function countPage(text, isEscaped)
{
var plain_text = text;
var parsed_text = "";
var max_page = 1;
if (plain_text.length > 0) {
if (isEscaped) {
parsed_text = plain_text;
}else{
parsed_text = plain_text.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
}
parsed_text = parsed_text.replace(/\r\n?/g, "\n");
// PAGE
parsed_text = parsed_text.replace(/[\n]?\[newpage\][\n]?/g , '[newpage]');
var page_array = parsed_text.split("[newpage]");
max_page = page_array.length;
}
return max_page;
}
function parseNovel(text, isEscaped){
var plain_text = text || '';
var parsed_text = "";
if (!(plain_text.length > 0)) {
return false;
}
if (isEscaped) {
parsed_text = plain_text;
} else {
parsed_text = plain_text.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
}
parsed_text = parsed_text.replace(/\r\n?/g, "\n");
// PAGE
parsed_text = parsed_text.replace(/[\n]?\[newpage\][\n]/g, '[newpage]');
// NEW_LINE
parsed_text = parsed_text.replace(/\n/g, "<br>");
var page_array = parsed_text.split("[newpage]");
parsed_text = "";
max_page = page_array.length;
var parsed_page = "";
for (var i = 0; i < max_page; i++) {
style = ' style="display:none;"';
parsed_page = '<div class="novel_article" id="page_' + (i + 1) + '"' + style + '>' + page_array[i] + '</div>';
//CHAPTER
temp_chapter_list = [];
temp_page = i + 1;
parsed_page = parsed_page.replace(/\[chapter:([^\]]+)\](<br>)?/g , push_chapter);
for(var j = 0; j < temp_chapter_list.length; j++){
chapter_list.push({ title:temp_chapter_list[j],
page:i+1,
id:j
});
}
//ILLUST
temp_illust_id_list = [];
parsed_page.replace(/\[pixivimage:([1-9][0-9]*)(-[1-9][0-9]*)?\](<br>)?/g, push_image_id);
parsed_text += parsed_page;
}
show_chapter_list();
if (window.location.hash != "") {
var hash = parseInt(window.location.hash.substring(1));
if (hash > 1 && hash <= max_page) {
cur_page = hash;
}
}
var preview_area = jQuery("#preview_area")[0];
if (preview_area.firstChild) {
preview_area.removeChild(preview_area.firstChild);
}
preview_area.innerHTML = parsed_text;
jump_to(cur_page);
if (illust_id_list.length > 0) {
jQuery.post(this.RPC_NOVEL_ILLUST_URL, {
'illust_ids': encodeURIComponent(illust_id_list.join(',')),
'mtime' : pixiv.context.updated || parseInt(+new Date / 1000),
'content_id': pixiv.context.illustId,
'x_restrict': pixiv.context.explicit,
'restrict' : pixiv.context.permission,
'user_id' : pixiv.context.userId,
'verbosity' : ''
}, 'json').done(this.onLoad);
}
return true;
}
function show_chapter_list(){
if(!jQuery("#novel_chapter")){
return;
}
if (chapter_list.length > 0) {
for (var i = 0; i < chapter_list.length; i++) {
var chapter = chapter_list[i];
jQuery("#novel_chapter .novel-outline").append('<li><a href="javascript:jump_to(' + chapter.page + ', true, ' + chapter.id + ');">' + chapter.title + '</a><em>' + chapter.page + '</em></li>');
jQuery("#novel_chapter").show();
}
}
}
/* 挿絵タグからイラストIDを抽出、HTMLへ置換 */
function push_image_id(str, p1, p2){
if (temp_illust_id_list.length != 0) {
return '<span class="preview_page" style="color:#ff0000;font-weight:bold;">[エラー : 1ページ内に挿入できる挿絵タグは1つまでです]</span>';
}
var image_str = p1;
if (p2 != undefined) {
image_str += p2;
}
if (jQuery.inArray(image_str, temp_illust_id_list) == -1) {
temp_illust_id_list.push(image_str);
}
if (jQuery.inArray(image_str, illust_id_list) == -1) {
illust_id_list.push(image_str);
}
return '<span class="novelimage novelimage_' + image_str + '" illust_id="'+ image_str + '"><a href="/member_illust.php?mode=medium&illust_id=' + p1 + '" target="_blank"><img src="http://source.pixiv.net/source/pixpedia/images/noimage300.gif" /></a></span>';
}
/* 章タイトルの一覧を取得 */
function push_chapter(str, p1, p2){
temp_chapter_list.push(p1);
return '<p class="chapter" id="chapter_'+ temp_page +'_'+ (temp_chapter_list.length - 1) +'">' + p1 + '</p>';
}
function parse_page(plain_text){
var parsed_page = plain_text;
//ILLUST
temp_illust_id_list = [];
parsed_page = parsed_page.replace(/\[pixivimage:([1-9][0-9]*)(-[1-9][0-9]*)?\]/g , push_image_id);
//JUMP(PAGE)
parsed_page = parsed_page.replace(/\[jump:([0-9^\]]+)\]/g , push_jump_page);
//JUMP(URI)
parsed_page = parsed_page.replace(/\[\[jumpuri:([^\]]+)> *([^\]]+)\]\]/g , push_jump_uri);
return parsed_page;
}
/* 小説内リンクタグをHTMLへ置換 */
function push_jump_page(str, p1){
var targetPage = parseInt(p1, 10);
if(targetPage > max_page || targetPage < 1){
return '<span class="preview_page" style="color:#ff0000;font-weight:bold;">[エラー : 小説内リンクに指定できないページです]</span>';
}
return '<a href="javascript:jump_to(' + targetPage + ', true);">' + targetPage + 'ページへ</a> ';
}
/* 小説外リンクタグをHTMLへ置換 */
function push_jump_uri(str, p1, p2){
var title = p1;
var uri = p2;
if (title===null || title==='' || uri===null || uri==='') {
return str;
}
title = title.replace(/^ +| +$/g, '');
if (title === '' || uri === '' || !isUrl(uri)) {
return str;
}
if (!isPixivUri(uri)) {
return '<a href="/jump.php?'+encodeURIComponent(uri)+'" target="_blank">' + title + '</a> ';
}
return '<a href="'+uri+'">' + title + '</a> ';
}
//Thank you for rafaeltds. http://snippets.dzone.com/posts/show/452
function isUrl(s) {
var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
return regexp.test(s);
}
function isPixivUri(uri) {
var regexp = /(http|https):\/\/(\w+\.pixiv\.net.*|p\.tl\/i\/\d+|p\.tl\/e\/\d+|p\.tl\/t\/\d+)/;
return regexp.test(uri);
}
function onLoad(response) {
if (!response || !$.isArray(response)){
return;
}
var id,html;
jQuery.each(response, function(i, illust_set) {
id = illust_set.id;
html = illust_set.html;
illust_html_list[id] = html;
});
jump_to(cur_page);
}
function page_prev(){
if(cur_page <= 1) return false;
jump_to(cur_page - 1, true);
return false;
}
function page_next(){
if(cur_page >= max_page) return false;
jump_to(cur_page + 1, true);
return false;
}
function jump_to(page, scroll, chapter_id){
if (cur_page != page) {
jQuery('#page_' + cur_page).css('display', 'none');
}
cur_page = page;
var target_page = jQuery('#page_' + cur_page).css('display', 'block');
if(!target_page.hasClass('parsed')){
target_page.html(parse_page(target_page.html())).addClass('parsed');
}
target_page.find('.novelimage').each(function() {
var el = jQuery(this);
if(el.hasClass('added')) return;
var illust_id = el.attr('illust_id');
if(illust_id === null) return;
if(!illust_html_list[illust_id]) return;
el.html(illust_html_list[illust_id]).addClass('added');
});
display_page_navi(cur_page);
if (scroll) {
if(window.location.hash !== '#' + cur_page){
window.location.replace('#' + cur_page);
}
if(chapter_id !== undefined){
jQuery(window).scrollTop(jQuery("#chapter_"+ cur_page + "_" + chapter_id).offset().top);
}else{
var target = jQuery('.works_display');
target.length || (target = jQuery('.novel_navi'));
jQuery(window).scrollTop(target.offset().top);
}
}
}
function display_page_navi(page){
jQuery(".button_prev").each(function() {
jQuery(this).css('visibility', (cur_page <= 1)? "hidden": "visible");
});
jQuery(".button_next").each(function() {
jQuery(this).css('visibility', (cur_page >= max_page)? "hidden": "visible");
});
jQuery(".page_num").each(function() {
jQuery(this).html(page + " / " + max_page + " ページ");
});
jQuery(".commentback_page").each(function() {
jQuery(this).val(page);
});
}
function add_marker() {
jQuery(".add_marker").each(function() {
this.innerHTML = "Loading ...";
});
var i_id = pixiv.context.illustId,
u_id = pixiv.user.id;
pixiv.api.post('rpc_marker.php', {
mode: 'save',
i_id: i_id,
u_id: u_id,
page: cur_page
}).done(function(data) {
if (data.page) {
message = '<span class="marker_page">' + data.page + '</span>ページにしおりをはさみました';
}
setTimeout(enable_add_marker, 30000); // avoid repeatedly clicking
jQuery(".add_marker").each(function() {
this.innerHTML = message;
});
jQuery(".marker_page").each(function() {
this.innerHTML = data.page;
});
jQuery(".marker_link").each(function() {
this.style.visibility = "visible";
});
});
}
function enable_marker_link(){
jQuery(".marker_link").each(function() {
jQuery(this).bind('click', function(){
jump_to(parseInt(jQuery('.marker_page')[0].innerHTML), true);
});
});
}
function enable_add_marker(){
jQuery(".add_marker").each(function() {
jQuery(this).html('<a href="javascript:void(0);" onclick="add_marker();">しおりをはさむ</a>');
});
}
function set_font_size(size){
var list = ["small", "big"];
jQuery('#preview_area').removeClass('novel_size_small novel_size_big');
if (jQuery.inArray(size, list) != -1) {
jQuery('#preview_area').addClass('novel_size_' + size);
}else{
size = '';
}
jQuery.cookie('novel_size', size, { expires: 365, path: '/'});
load_font_config();
return false;
}
function toggle_font_family(){
var class_name = 'novel_font_pgothic';
var bool = jQuery('#preview_area').toggleClass(class_name).hasClass(class_name);
jQuery.cookie('novel_font', (bool)?'pgothic':'', { expires: 365, path: '/'});
load_font_config();
return false;
}
function toggle_line_height(){
var class_name = 'novel_line_narrow';
var bool = jQuery('#preview_area').toggleClass(class_name).hasClass(class_name);
jQuery.cookie('novel_line', (bool)?'narrow':'', { expires: 365, path: '/'});
load_font_config();
return false;
}
function update_novel_navi(cookie_name, class_name, list){
var value = jQuery.cookie(cookie_name);
if (jQuery.inArray(value, list) != -1) {
jQuery('#preview_area').addClass(cookie_name + '_' + value);
}else{
value = "";
}
jQuery(class_name).each(function(){
if (jQuery(this).attr("cvalue") == value) {
jQuery(this).addClass("on");
} else {
jQuery(this).removeClass("on");
}
});
}
URLのパーサがあまりに適当なので、なんとかするか諦めるか、を決める。
/[-A-Za-z0-9._~!$&'()*+,;=%:/@.?#]+/
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.