2012年12月03日 (月) 05:27
【小説家になろう】の作品には小説コード(Nコード)ってのが設定されています。
このコードに対応する短編作品または連載作品を電子書籍用ファイル(.epub)として保存するプログラムを作ってみました。
動作はOS:Linuxのみで確認。たぶんアンドロイドでも動く。rubyが環境中で動くことが前提
windowsでは動かしてないから、動くかわからない。たぶん、ファイルパス指定のところを「/」区切りではなく「\」区切りに変えてあげれば動くと思われる。
【使い方】
1,Ruby1.9をインストールする
2,gepub(指定したファイルをepubに変換する機能)をインストールする
# gem install gepub
3,下記の[ePubniNarou.ini][ePubniNarou.rb]をそれぞれメモ帳にコピー(--- なんとか ---の行はいれない)。ファイル名を「--- なんとか ---」の何とかで指定された奴にして保存。
4,保存した2ファイルを適当なフォルダにいれる(例として~/ePubniNarou/以下に格納したとする)
$ cd ~/ePubniNarou
$ ls
ePubniNarou.ini ePubniNarou.rb
$ ruby -v
ruby 1.9.3p0 (2011-10-30 revision 33570) [i686-linux]
$ ruby ePubniNarou.rb n7148bi
出力完了!
$ ls
ePubniNarou.ini ePubniNarou.rb n7148bi.epub
【Q&A】
『使ってみたら、家のパソコンがこわれた』『使ったら、保存していたファイルが消えたんですが』など
→利用は自己責任でお願いします。
『epubファイルの表示の仕方がわかんね』
→FireFoxにEPUBReaderいれてみたり、なんかそれっぽいブラウザを探しましょう
『でてきたepubファイルがしょぼい』
→[ePubniNarou.ini]の中を改造してください
[css/XXXXX] とか書かれているXXXXXクラスのフォーマットを変更します。
具体的には
---ePubniNarou.iniに追記---
#追記内容 ←こんなふうに「#〜」とコメントをかける
#作者名の表示を変更
[css/.novel_writername]
#枠で囲む
border=dotted orange 10px
#斜体表示する
font-style=italic
---ePubniNarou.iniに追記ここまで---
すると内部的に
.novel_writername {
border:dotted orange 10px;
font-style:italic;
}
というCSSで表現されます。きっと。
記.設定ファイル(.ini)とプログラム(.rb)
--- ePubniNarou.ini ---
[url]
ncode_url=/ncode.syosetu.com/
[css/div.novel_title]
font-size=1.2em
font-weight=bold
[css/.novel_title2]
font-size=1.8em
font-weight=bold
[css/.novel_subtitle]
font-size=1.2em
font-weight=bold
--- ePubniNarou.rb ---
# coding: utf-8
#↑の行が一行目に来るようにメモ帳に貼り付ける
require 'open-uri'
require 'fileutils'
require 'kconv'
require 'gepub'
#情報
$n_auther = ''
$n_title = ''
$n_update = ''
$styleget_flg = false
#iniファイル読込
#ファイル内の[]で囲まれた要素を第一要素に
#a=b のaを第二要素にして、bの値を格納
#先頭が#のものはコメントと見倣す
def readIniFile(fname)
if not File.exist?(fname) then
return nil
end
#二次元ハッシュ作成
res = Hash.new { |hash,key| hash[key] = Hash.new {} }
#ファイル読込
File.open(fname, "r") do |file|
ini_index = "def"
file.each_line do |line|
tmpline = line.strip
if tmpline.to_s.empty? or tmpline[0] == "#" then
#skip
elsif tmpline =~ /^\[.*\]$/ then
ini_index = tmpline.gsub('[', '').gsub(']', '').strip
elsif tmpline.index("=") then
res[ini_index][line.split("=")[0].strip] = line.split("=")[1].strip
end
end
end
return res
end
#指定されたページを開き、
#ページ内の<div class="novel_bar">または<div class="novel_title">行から
#</div><!--novel_color-->行までをtempfileに出力する
#ただしtmpfileが開けないときと、webページタイトルが「エラー」の時はnilを帰す
def readNarouPage(url , tmpdir)
begin
putsflg = nil
Dir.mkdir(tmpdir)
File.open("#{tmpdir}/index.html", 'w') { |fline|
open(url){|fweb|
fweb.each_line {|webline| #取得して1行ずつ読み出す
getline = webline.toutf8 #取得はASCII-8BIT形式でされるので文字コード変換しないと日本語比較できない
#ページ内の<div class="novel_bar">行から</div><!--novel_color-->行までを出力
if getline =~ /<div class="novel_bar">/ then
putsflg = 'text'
elsif getline =~ /<div class="novel_title">/ then
putsflg = 'title'
elsif getline =~ /<title>エラー<\/title>/ then
puts("そのページは存在しません")
return nil
elsif getline =~ /<title>.*<\/title>/ then
fline.write('<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />')
fline.write(getline) # <title>
if $styleget_flg then
styls_place = "../styles.css"
else
#タイトルのとき
styls_place = "./styles.css"
$styleget_flg = true
end
fline.write("<link rel='stylesheet' href='#{styls_place}' type='text/css' media='screen,print'/>")
fline.write('</head>
<body>')
$n_title = getline.gsub(/<title>/, '')
$n_title = $n_title.gsub(/<\/title>/, '')
elsif getline =~ /作者:<a href=.*\/a>/ then
$n_auther = getline.gsub(/<\/a>/, '')
$n_auther = $n_auther.gsub(/.*作者:<a href=.*">/, '')
elsif getline =~ /<meta name="WWWC" content=.*>/ then
$n_update = getline.gsub(/" \/>.*/, '')
$n_update = $n_update.gsub(/<meta name="WWWC" content="/, '')
$n_update = $n_update.gsub(/ /, 'T') + 'Z'
$n_update = $n_update.gsub(/\//, '-') + ':00Z'
elsif getline =~ /<\/div><!--novel_color-->/ then
break
end
if putsflg == 'title' then
getline.gsub!(/<a href="\/#{$code_id}/, '<a href=".')
fline.write(getline)
elsif putsflg == 'text' then
getline.gsub!(/<a href="\/#{$code_id}/, '<a href="..')
fline.write(getline)
end
}
}
fline.write("</body></html>")
}
page = 0
if putsflg == 'title' then
while readNarouPage("#{url}/#{page + 1}/","#{tmpdir}/#{page + 1}")
page += 1
end
end
return page
rescue
#余計につくられたフォルダを削除
#puts "rm_r " + tmpdir
FileUtils.rm_r( tmpdir,:force=>true)
return nil
end
end
#与えられた情報からCSSファイルを作る
#set_hashの中で、キーが「css/XXX」のとき、XXXの要素名に対してメンバーを設定する
def makeEpubCss(fpath,set_hash)
begin
#ひたすら書込み
File.open(fpath,'w'){|cssf|
#変数がハッシュかを判定
if not set_hash.instance_of?(Hash) then
return nil # abnomal end
end
set_hash.each {|element,attr_hash|
if element =~ /^css\// then
if not attr_hash.instance_of?(Hash) then
break
end
#要素数が1以上の時にやりましょう
if attr_hash.length > 0 then
cssf.write("#{element.split('/')[1]}{\n")
attr_hash.each {|prop,val|
val = val.downcase
if val == "true" then
#多分boldなど想定
cssf.write("\t#{prop};\n")
elsif val != "false" then
cssf.write("\t#{prop}: #{val};\n")
end
}
cssf.write("}\n")
end
end
}
}
rescue
return nil # abnomal end
end
end
################################################################################
#ここから下
#メイン処理開始
################################################################################
#コマンドラインから渡された引数をもらう(アルファベットは小文字に変換)
$code_id = ARGV[0].downcase
if $code_id == nil or ( $code_id[0] != 'n') then
puts("nで始まるパラメータを入力してください") #sコード(シリーズ物)には未対応
exit
end
#ePubniNarou.iniファイルの読込
pgpath = File.dirname(__FILE__)
ini_set = readIniFile("#{pgpath}/ePubniNarou.ini")
#一時作業フォルダ作成
workdir = ""
workdir << pgpath << "/ePubniNarou_temp"
if Dir.exist?(workdir) then
FileUtils.rm_r(workdir,:force=>true)
end
epubdir = "#{workdir}/#{ARGV[0]}"
Dir.mkdir(workdir)
open_uri = "http:/"
open_uri << ini_set['url']['ncode_url'] << ARGV[0]
page = readNarouPage(open_uri,epubdir) # 短編だと0が帰ってくる。連作だと話数が帰ってくる(最小1)
#CSSをつくる
if not makeEpubCss("#{epubdir}/styles.css",ini_set) then
puts 'CSSファイルの作成になんか失敗した'
end
#ページが0以上の数なら
if page then
builder = GEPUB::Builder.new {
language 'ja'
unique_identifier open_uri, 'BookID', 'URL'
title $n_title
subtitle '[ePubになろう]により作成'
creator $n_auther
contributors 'Denshobu', 'Asagaya Densho', 'Shonan Densho Teidan', 'eMagazine Torutaru'
date $n_update
resources(:workdir => "#{epubdir}/") {
#cover_image 'img/image1.jpg' => 'image1.jpg'
ordered {
#目次の作成
if page == 0 then
#短編の場合:チャプターとかはいらない
file 'index.html'
else
i = 0
while i < page do
if i == 0 then
file 'index.html'
heading 'Top'
else
file "#{i}/index.html"
heading "Chapter #{i}"
end
i += 1
end
end
file 'styles.css'
}
}
}
builder.generate_epub("#{pgpath}.epub")
end
#作業フォルダを削除
FileUtils.rm_r(workdir,:force=>true)
#終了メッセージ
puts "出力完了!"