diff --git a/app/src/main/assets/epub/chapter.html b/app/src/main/assets/epub/chapter.html new file mode 100644 index 000000000..57b8bce01 --- /dev/null +++ b/app/src/main/assets/epub/chapter.html @@ -0,0 +1,17 @@ + + + + + Chapter + + + + + +

{title}

+{content} + + \ No newline at end of file diff --git a/app/src/main/assets/epub/cover.html b/app/src/main/assets/epub/cover.html new file mode 100644 index 000000000..268cc3f85 --- /dev/null +++ b/app/src/main/assets/epub/cover.html @@ -0,0 +1,22 @@ + + + + + Cover + + + +
+

{name}

+
{author} / 著
+ + \ No newline at end of file diff --git a/app/src/main/assets/epub/fonts.css b/app/src/main/assets/epub/fonts.css new file mode 100644 index 000000000..3457a6511 --- /dev/null +++ b/app/src/main/assets/epub/fonts.css @@ -0,0 +1,267 @@ +@charset "utf-8"; +/*---常用---*/ + +@font-face { + font-family: "zw"; + src: + local("宋体"),local("明体"),local("明朝"), + local("Songti"),local("Songti SC"),local("Songti TC"), /*iOS6+iBooks3*/ + local("Song S"),local("Song T"),local("STBShusong"),local("TBMincho"),local("HYMyeongJo"), /*Kindle Paperwihite*/ + local("DK-SONGTI"), + url(../Fonts/zw.ttf), + url(res:///opt/sony/ebook/FONT/zw.ttf), + url(res:///Data/FONT/zw.ttf), + url(res:///opt/sony/ebook/FONT/tt0011m_.ttf), + url(res:///ebook/fonts/../../mnt/sdcard/fonts/zw.ttf), + url(res:///ebook/fonts/../../mnt/extsd/fonts/zw.ttf), + url(res:///ebook/fonts/zw.ttf), + url(res:///ebook/fonts/DroidSansFallback.ttf), + url(res:///fonts/ttf/zw.ttf), + url(res:///../../media/mmcblk0p1/fonts/zw.ttf), + url(file:///mnt/us/DK_System/system/fonts/zw.ttf), /*Duokan Old Path*/ + url(file:///mnt/us/DK_System/xKindle/res/userfonts/zw.ttf), /*Duokan 2012 Path*/ + url(res:///abook/fonts/zw.ttf), + url(res:///system/fonts/zw.ttf), + url(res:///system/media/sdcard/fonts/zw.ttf), + url(res:///media/fonts/zw.ttf), + url(res:///sdcard/fonts/zw.ttf), + url(res:///system/fonts/DroidSansFallback.ttf), + url(res:///mnt/MOVIFAT/font/zw.ttf), + url(res:///media/flash/fonts/zw.ttf), + url(res:///media/sd/fonts/zw.ttf), + url(res:///opt/onyx/arm/lib/fonts/AdobeHeitiStd-Regular.otf), + url(res:///../../fonts/zw.ttf), + url(res:///../fonts/zw.ttf), + url(../../../../../zw.ttf), /*EpubReaderI*/ + url(res:///mnt/sdcard/fonts/zw.ttf), /*Nook for Android: fonts in TF Card*/ + url(res:///fonts/zw.ttf), /*ADE1,8, 2.0 Program Path*/ + url(res:///../../../../Windows/fonts/zw.ttf); + /*ADE1,8, 2.0 Windows Path*/; +} + +@font-face { + font-family: "fs"; + src: + local("amasis30"),local("仿宋"),local("仿宋_GB2312"), + local("Yuanti"),local("Yuanti SC"),local("Yuanti TC"), /*iOS6+iBooks3*/ + local("DK-FANGSONG"), + url(../Fonts/fs.ttf), + url(res:///opt/sony/ebook/FONT/fs.ttf), + url(res:///Data/FONT/fs.ttf), + url(res:///opt/sony/ebook/FONT/tt0011m_.ttf), + url(res:///ebook/fonts/../../mnt/sdcard/fonts/fs.ttf), + url(res:///ebook/fonts/../../mnt/extsd/fonts/fs.ttf), + url(res:///ebook/fonts/fs.ttf), + url(res:///ebook/fonts/DroidSansFallback.ttf), + url(res:///fonts/ttf/fs.ttf), + url(res:///../../media/mmcblk0p1/fonts/fs.ttf), + url(file:///mnt/us/DK_System/system/fonts/fs.ttf), /*Duokan Old Path*/ + url(file:///mnt/us/DK_System/xKindle/res/userfonts/fs.ttf), /*Duokan 2012 Path*/ + url(res:///abook/fonts/fs.ttf), + url(res:///system/fonts/fs.ttf), + url(res:///system/media/sdcard/fonts/fs.ttf), + url(res:///media/fonts/fs.ttf), + url(res:///sdcard/fonts/fs.ttf), + url(res:///system/fonts/DroidSansFallback.ttf), + url(res:///mnt/MOVIFAT/font/fs.ttf), + url(res:///media/flash/fonts/fs.ttf), + url(res:///media/sd/fonts/fs.ttf), + url(res:///opt/onyx/arm/lib/fonts/AdobeHeitiStd-Regular.otf), + url(res:///../../fonts/fs.ttf), + url(res:///../fonts/fs.ttf), + url(../../../../../fs.ttf), /*EpubReaderI*/ + url(res:///mnt/sdcard/fonts/fs.ttf), /*Nook for Android: fonts in TF Card*/ + url(res:///fonts/fs.ttf), /*ADE1,8, 2.0 Program Path*/ + url(res:///../../../../Windows/fonts/fs.ttf); + /*ADE1,8, 2.0 Windows Path*/; +} + +@font-face { + font-family: "kt"; + src: + local("Caecilia"),local("楷体"),local("楷体_GB2312"), + local("Kaiti"),local("Kaiti SC"),local("Kaiti TC"), /*iOS6+iBooks3*/ + local("MKai PRC"),local("MKaiGB18030C-Medium"),local("MKaiGB18030C-Bold"), /*Kindle Paperwihite*/ + local("DK-KAITI"), + url(../Fonts/kt.ttf), + url(res:///opt/sony/ebook/FONT/kt.ttf), + url(res:///Data/FONT/kt.ttf), + url(res:///opt/sony/ebook/FONT/tt0011m_.ttf), + url(res:///ebook/fonts/../../mnt/sdcard/fonts/kt.ttf), + url(res:///ebook/fonts/../../mnt/extsd/fonts/kt.ttf), + url(res:///ebook/fonts/kt.ttf), + url(res:///ebook/fonts/DroidSansFallback.ttf), + url(res:///fonts/ttf/kt.ttf), + url(res:///../../media/mmcblk0p1/fonts/kt.ttf), + url(file:///mnt/us/DK_System/system/fonts/kt.ttf), /*Duokan Old Path*/ + url(file:///mnt/us/DK_System/xKindle/res/userfonts/kt.ttf), /*Duokan 2012 Path*/ + url(res:///abook/fonts/kt.ttf), + url(res:///system/fonts/kt.ttf), + url(res:///system/media/sdcard/fonts/kt.ttf), + url(res:///media/fonts/kt.ttf), + url(res:///sdcard/fonts/kt.ttf), + url(res:///system/fonts/DroidSansFallback.ttf), + url(res:///mnt/MOVIFAT/font/kt.ttf), + url(res:///media/flash/fonts/kt.ttf), + url(res:///media/sd/fonts/kt.ttf), + url(res:///opt/onyx/arm/lib/fonts/AdobeHeitiStd-Regular.otf), + url(res:///../../fonts/kt.ttf), + url(res:///../fonts/kt.ttf), + url(../../../../../kt.ttf), /*EpubReaderI*/ + url(res:///mnt/sdcard/fonts/kt.ttf), /*Nook for Android: fonts in TF Card*/ + url(res:///fonts/kt.ttf), /*ADE1,8, 2.0 Program Path*/ + url(res:///../../../../Windows/fonts/kt.ttf); + /*ADE1,8, 2.0 Windows Path*/; +} + +@font-face { + font-family: "ht"; + src: + local("黑体"),local("微软雅黑"), + local("Heiti"),local("Heiti SC"),local("Heiti TC"), /*iOS6+iBooks3*/ + local("MYing Hei S"),local("MYing Hei T"),local("TBGothic"), /*Kindle Paperwihite*/ + local("DK-HEITI"), + url(../Fonts/ht.ttf), + url(res:///opt/sony/ebook/FONT/ht.ttf), + url(res:///Data/FONT/ht.ttf), + url(res:///opt/sony/ebook/FONT/tt0011m_.ttf), + url(res:///ebook/fonts/../../mnt/sdcard/fonts/ht.ttf), + url(res:///ebook/fonts/../../mnt/extsd/fonts/ht.ttf), + url(res:///ebook/fonts/ht.ttf), + url(res:///ebook/fonts/DroidSansFallback.ttf), + url(res:///fonts/ttf/ht.ttf), + url(res:///../../media/mmcblk0p1/fonts/ht.ttf), + url(file:///mnt/us/DK_System/system/fonts/ht.ttf), /*Duokan Old Path*/ + url(file:///mnt/us/DK_System/xKindle/res/userfonts/ht.ttf), /*Duokan 2012 Path*/ + url(res:///abook/fonts/ht.ttf), + url(res:///system/fonts/ht.ttf), + url(res:///system/media/sdcard/fonts/ht.ttf), + url(res:///media/fonts/ht.ttf), + url(res:///sdcard/fonts/ht.ttf), + url(res:///system/fonts/DroidSansFallback.ttf), + url(res:///mnt/MOVIFAT/font/ht.ttf), + url(res:///media/flash/fonts/ht.ttf), + url(res:///media/sd/fonts/ht.ttf), + url(res:///opt/onyx/arm/lib/fonts/AdobeHeitiStd-Regular.otf), + url(res:///../../fonts/ht.ttf), + url(res:///../fonts/ht.ttf), + url(../../../../../ht.ttf), /*EpubReaderI*/ + url(res:///mnt/sdcard/fonts/ht.ttf), /*Nook for Android: fonts in TF Card*/ + url(res:///fonts/ht.ttf), /*ADE1,8, 2.0 Program Path*/ + url(res:///../../../../Windows/fonts/ht.ttf); + /*ADE1,8, 2.0 Windows Path*/; +} +@font-face { + font-family:"h1"; + src: + local("方正兰亭特黑长_GBK"),local("方正兰亭特黑长简体"),local("方正兰亭特黑长繁体"), + local("LantingTeheichang"), + local("Yuanti"),local("Yuanti SC"),local("Yuanti TC"), + local("DK-HEITI"), + url(../Fonts/h1.ttf), + url(res:///opt/sony/ebook/FONT/h1.ttf), + url(res:///Data/FONT/h1.ttf), + url(res:///opt/sony/ebook/FONT/tt0011m_.ttf), + url(res:///ebook/fonts/../../mnt/sdcard/fonts/h1.ttf), + url(res:///ebook/fonts/../../mnt/extsd/fonts/h1.ttf), + url(res:///ebook/fonts/h1.ttf), + url(res:///ebook/fonts/DroidSansFallback.ttf), + url(res:///fonts/ttf/h1.ttf), + url(res:///../../media/mmcblk0p1/fonts/h1.ttf), + url(file:///mnt/us/DK_System/system/fonts/h1.ttf), /*Duokan Old Path*/ + url(file:///mnt/us/DK_System/xKindle/res/userfonts/h1.ttf), /*Duokan 2012 Path*/ + url(res:///abook/fonts/h1.ttf), + url(res:///system/fonts/h1.ttf), + url(res:///system/media/sdcard/fonts/h1.ttf), + url(res:///media/fonts/h1.ttf), + url(res:///sdcard/fonts/h1.ttf), + url(res:///system/fonts/DroidSansFallback.ttf), + url(res:///mnt/MOVIFAT/font/h1.ttf), + url(res:///media/flash/fonts/h1.ttf), + url(res:///media/sd/fonts/h1.ttf), + url(res:///opt/onyx/arm/lib/fonts/AdobeHeitiStd-Regular.otf), + url(res:///../../fonts/h1.ttf), + url(res:///../fonts/h1.ttf), + url(../../../../../h1.ttf), /*EpubReaderI*/ + url(res:///mnt/sdcard/fonts/h1.ttf), /*Nook for Android: fonts in TF Card*/ + url(res:///fonts/h1.ttf), /*ADE1,8, 2.0 Program Path*/ + url(res:///../../../../Windows/fonts/h1.ttf); /*ADE1,8, 2.0 Windows Path*/ +} +@font-face { + font-family:"h2"; + src: + local("方正大标宋_GBK"),local("方正大标宋简体"),local("方正大标宋繁体"), + local("Dabiaosong"), + local("Heiti"),local("Heiti SC"),local("Heiti TC"), + local("DK-XIAOBIAOSONG"), + url(../Fonts/h2.ttf), + url(res:///opt/sony/ebook/FONT/h2.ttf), + url(res:///Data/FONT/h2.ttf), + url(res:///opt/sony/ebook/FONT/tt0011m_.ttf), + url(res:///ebook/fonts/../../mnt/sdcard/fonts/h2.ttf), + url(res:///ebook/fonts/../../mnt/extsd/fonts/h2.ttf), + url(res:///ebook/fonts/h2.ttf), + url(res:///ebook/fonts/DroidSansFallback.ttf), + url(res:///fonts/ttf/h2.ttf), + url(res:///../../media/mmcblk0p1/fonts/h2.ttf), + url(file:///mnt/us/DK_System/system/fonts/h2.ttf), /*Duokan Old Path*/ + url(file:///mnt/us/DK_System/xKindle/res/userfonts/h2.ttf), /*Duokan 2012 Path*/ + url(res:///abook/fonts/h2.ttf), + url(res:///system/fonts/h2.ttf), + url(res:///system/media/sdcard/fonts/h2.ttf), + url(res:///media/fonts/h2.ttf), + url(res:///sdcard/fonts/h2.ttf), + url(res:///system/fonts/DroidSansFallback.ttf), + url(res:///mnt/MOVIFAT/font/h2.ttf), + url(res:///media/flash/fonts/h2.ttf), + url(res:///media/sd/fonts/h2.ttf), + url(res:///opt/onyx/arm/lib/fonts/AdobeHeitiStd-Regular.otf), + url(res:///../../fonts/h2.ttf), + url(res:///../fonts/h2.ttf), + url(../../../../../h2.ttf), /*EpubReaderI*/ + url(res:///mnt/sdcard/fonts/h2.ttf), /*Nook for Android: fonts in TF Card*/ + url(res:///fonts/h2.ttf), /*ADE1,8, 2.0 Program Path*/ + url(res:///../../../../Windows/fonts/h2.ttf); /*ADE1,8, 2.0 Windows Path*/ +} + +@font-face { + font-family:"h3"; + src: + local("方正华隶_GBK"),local("方正行黑简体"),local("方正行黑繁体"), + local("Yuanti"),local("Yuanti SC"),local("Yuanti TC"), + local("DK-FANGSONG"), + url(../Fonts/h3.ttf), + url(res:///opt/sony/ebook/FONT/h3.ttf), + url(res:///Data/FONT/h3.ttf), + url(res:///opt/sony/ebook/FONT/tt0011m_.ttf), + url(res:///ebook/fonts/../../mnt/sdcard/fonts/h3.ttf), + url(res:///ebook/fonts/../../mnt/extsd/fonts/h3.ttf), + url(res:///ebook/fonts/h3.ttf), + url(res:///ebook/fonts/DroidSansFallback.ttf), + url(res:///fonts/ttf/h3.ttf), + url(res:///../../media/mmcblk0p1/fonts/h3.ttf), + url(file:///mnt/us/DK_System/system/fonts/h3.ttf), /*Duokan Old Path*/ + url(file:///mnt/us/DK_System/xKindle/res/userfonts/h3.ttf), /*Duokan 2012 Path*/ + url(res:///abook/fonts/h3.ttf), + url(res:///system/fonts/h3.ttf), + url(res:///system/media/sdcard/fonts/h3.ttf), + url(res:///media/fonts/h3.ttf), + url(res:///sdcard/fonts/h3.ttf), + url(res:///system/fonts/DroidSansFallback.ttf), + url(res:///mnt/MOVIFAT/font/h3.ttf), + url(res:///media/flash/fonts/h3.ttf), + url(res:///media/sd/fonts/h3.ttf), + url(res:///opt/onyx/arm/lib/fonts/AdobeHeitiStd-Regular.otf), + url(res:///../../fonts/h3.ttf), + url(res:///../fonts/h3.ttf), + url(../../../../../h3.ttf), /*EpubReaderI*/ + url(res:///mnt/sdcard/fonts/h3.ttf), /*Nook for Android: fonts in TF Card*/ + url(res:///fonts/h3.ttf), /*ADE1,8, 2.0 Program Path*/ + url(res:///../../../../Windows/fonts/h3.ttf); /*ADE1,8, 2.0 Windows Path*/ +} + +@font-face { + font-family:"luohua"; + src:local("汉仪落花体"), + url("../Fonts/hylh.ttf"); +} \ No newline at end of file diff --git a/app/src/main/assets/epub/intro.html b/app/src/main/assets/epub/intro.html new file mode 100644 index 000000000..85eb28a63 --- /dev/null +++ b/app/src/main/assets/epub/intro.html @@ -0,0 +1,12 @@ + + + + + Intro + + + + +

内容简介

{intro} + diff --git a/app/src/main/assets/epub/logo.png b/app/src/main/assets/epub/logo.png new file mode 100644 index 000000000..104d1777c Binary files /dev/null and b/app/src/main/assets/epub/logo.png differ diff --git a/app/src/main/assets/epub/main.css b/app/src/main/assets/epub/main.css new file mode 100644 index 000000000..fcb287442 --- /dev/null +++ b/app/src/main/assets/epub/main.css @@ -0,0 +1,551 @@ +@charset "utf-8"; +@import url("../Styles/fonts.css"); +body { + padding: 0%; + margin-top: 0%; + margin-bottom: 0%; + margin-left: 0.5%; + margin-right: 0.5%; + line-height: 130%; + text-align: justify; + font-family: "DK-SONGTI","st","宋体","zw",sans-serif; +} + +p { + text-align: justify; + text-indent: 2em; + line-height: 130%; + margin-right: 0.5%; + margin-left: 0.5%; + font-family: "DK-SONGTI","st","宋体","zw",sans-serif; +} +p.kaiti { + font-family: "DK-KAITI","kt","楷体","zw",serif; +} + +p.fangsong { + font-family: "DK-FANGSONG","fs","仿宋","zw",serif; +} + +span.xinli { + font-family: "DK-KAITI","kt","楷体","zw",serif; + color: #4e753f; +} +/** 英文斜体字 **/ +span.english{ + font-style: italic; +} +div { + margin: 0px; + padding: 0px; + line-height: 120%; + text-align: justify; + font-family: "zw"; +} +div.foot { + text-indent: 2em; + margin: 30% 5% 0 5%; + padding: 8px 0; +} +p.foot { + font-family: "DK-KAITI","kt","楷体","zw",serif; +} + +/*扉页*/ +.booksubtitle { + padding: 10px 0 0px 0; + text-indent: 0em; + font-size: 75%; + font-family: "ht"; +} + +.booktitle { + padding: 9% 0 0 0; + font-size: 1.3em; + font-family: "方正小标宋_GBK","DK-XIAOBIAOSONG"; + font-weight: normal; + text-indent: 0em; + color: #000; + text-align: center; + line-height: 1.6; +} + +.booktitle0 { + font-size: 1.2em; + font-family: "fs"; + text-indent: 0em; + text-align: center; + line-height: 1.8; +} + +.booktitle1 { + padding: 0 0 0 0; + font-size: 0.85em; + font-family: "fs"; + text-indent: 0em; + text-align: center; + line-height: 1.6; +} + +.bookauthor { + font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif; + padding: 5% 5px 0px 5px; + text-indent: 0em; + text-align: center; + color: #000; + font-size: 90%; + line-height: 1.3; +} + +.booktranslator { + padding: 1% 5px 0px 5px; + text-indent: 0em; + text-align: center; + font-size: 85%; + line-height: 1.3; +} + +.bookpub { + font-family: "DK-KAITI","kt","楷体","楷体_gb2312"; + padding: 30% 5px 5px 5px; + text-indent: 0em; + color: #000; + text-align: center; + font-size: 80%; +} + +/*标题页*/ +body.head { + background-repeat:no-repeat no-repeat; + background-size:160px 229px; + background-position:bottom right; + background-attachment:fixed; +} + +body.xhead { + background-color: #FDF5E6; +} + +h1.head { + font-family: "DK-HEITI",黑体,sans-serif; + font-size: 1.2em; + font-weight: bold; + color: #311a02; + text-indent: 0em; + font-weight: normal; + duokan-text-indent: 0em; + padding: auto; + text-align: center; + margin-top: -8em; +} + +div.head { + border: solid 2px #ffffff; + padding: 2px; + margin: 2em auto 0.7em auto; + text-align: center; + width: 1em; +} + +h1.head b { + font-family: "方正小标宋_GBK","DK-XIAOBIAOSONG"; + font-weight: bold; + font-size: 1.2em; + text-align: center; + text-indent: 0em; + duokan-text-indent: 0em; + color: #311a02; + margin: 0.5em auto; + line-height: 140%; +} + +div.back { + text-align: center; + text-indent: 0em; + duokan-text-indent: 0em; + margin: 4em auto; +} + +img.back { + width: 70%; +} +img.back2 { + width: 40%; + margin: 2em 0 0 0; +} +/*正文*/ +/**楷体引文**/ +.titou { + font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif; +} +.yinwen { + font-family: "DK-KAITI","kt","楷体","zw",serif; + margin-left: 2em; + text-indent: 0em; +} +.nicename { + font-family: "DK-HEITI",黑体,sans-serif; + font-weight: bold; + font-size: 0.9em; +} +body.head3 { + background-color: #a7bdcc; + color: #354f66; +} + +body.head4 { + background-color: #bfd19b; + color: #4e753f; +} + +h2.head { + font-family: "小标宋"; + text-align: left; + font-weight: bold; + font-size: 1.1em; + margin: -3em 2em 2em 0; + color: #3f83e8; + line-height: 140%; +} + +h2.head span { + font-family: "仿宋"; + font-size: 0.7em; + background-color: #3f83e8; + border-radius: 9px; + padding: 4px; + color: #fff; +} + + +div.logo { + margin: -2em 0% 0 0; + text-align: right; +} + +img.logo { + width: 40%; +} +.imgl { + /*图片居右*/ + margin: -8.8em 1em 4em 0em; + width: 80%; + text-align: right; +} + +h1.head { + line-height:130%; + font-size:1.4em; + text-align: center; + color: #BA2213; + font-weight: bold; + margin-top: 2em; + margin-bottom: 1em; + font-family: "方正小标宋_GBK","DK-XIAOBIAOSONG"; + +} +h3 { + font-family: "DK-HEITI",黑体,sans-serif; + font-size: 1.1em; + margin: 1em 0; + border-left: 1.2em solid #00a1e9; + line-height: 120%; + padding-left: 3px; + color: #00a1e9; +} +h4 { + font-family: "DK-HEITI",黑体,sans-serif; + font-size: 1.1em; + text-align: center; + margin: 1em 0; + line-height: 120%; + color: #000; +} +h1.post { + font-family: "方正小标宋_GBK","DK-XIAOBIAOSONG"; + text-align: center; + font-size: 1.3em; + color: #026fca; + margin: 3em auto 2em auto; +} +.banquan { + font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif; + text-align: left; + color: #000; + font-size:1.1em; + margin-bottom:1em; + text-indent: 1em; + duokan-text-indent: 1em; +} +p.post { + font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif; +} +p.zy { + font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif; + margin: 1em 0 0 1em; + padding: 5px 0px 5px 10px; + text-indent: 0em; + border-left: 5px solid #a9b5c1; +} +.sign { + font-family: "DK-KAITI","kt","楷体","zw",serif; + margin: 1em 2px 0 auto; + text-align: right; + font-size: 0.8em; + text-indent: 0em; + duokan-text-indent: 0em; +} + +.mark { + font-family: "DK-HEITI",黑体,sans-serif; + font-size: 0.9em; + color: #fff; + text-indent: 0em; + duokan-text-indent: 0em; + background-color: maroon; + text-align: center; + padding: 0px; + margin: 2em 30%; +} + +/*出版社*/ +.chubanshe img{ + width:106px; + height:28px; +} +.chubanshe { + margin-top:20px; +} +.cr { + font-size:0.9em; +} + +/*多看画廊*/ +div.duokan-image-single { + text-align: center; + margin: 0.5em auto; /*插图盒子上下外边距为0.5em,左右设置auto是为了水平居中这个盒子*/ +} +img.picture-80 { + margin: 0; /*清除img元素的外边距*/ + width: 80%; /*预览窗口的宽度*/ + box-shadow: 3px 3px 10px #bfbfbf; /*给图片添加阴影效果*/ +} +p.duokan-image-maintitle { + margin: 1em 0 0; /*图片说明的段间距*/ + font-family: "楷体"; /*图片说明使用的字体*/ + font-size: 0.9em; /*字体大小*/ + text-indent: 0; /*首行缩进为零,当你使用单标签p来指定首行缩进为2em时,记得在需要居中的文本中清除缩进,因为样式是叠加的*/ + text-align: center; /*图片说明水平居中*/ + color: #a52a2a; /*字体颜色*/ + line-height: 1.25em; /*行高,防止有很长的图片说明*/ +} + + +/*制作说明页*/ +body.description { + background-image: url(../Images/001.png); + background-position: bottom center; + background-repeat: no-repeat; + background-size: cover; + padding: 25% 10% 0; + font-size: 0.9em; +} + +div.description-body { + width: 55%; + padding: 2em 1.3em; + border-radius: 0.5em; + font-size: 0.9em; + border-style: solid; + border-color: #393939; + border-width: 0.3em; + border-radius: 5em; + background-color: #5a5a5a; + box-shadow: 2px 2px 3px #828281; +} + +h1.description-title { + text-align: center; + font-family: "黑体"; + font-size: 1.2em; + margin: 0 0 1em 0; + color: #FF9; + text-shadow: 1px 1px 0 black; +} + +p.description-text { + color: #f9ddd2; + font-family: "准圆"; + margin: 0; + text-align: justify; + text-indent: 0; + duokan-text-indent: 0; +} + +hr.description-hr { + margin: 0.5em -1em; + border-style: dotted; + border-color: #9C9; + border-width: 0.05em 0 0 0; +} + +p.tips { + text-align: justify; + text-indent: 0; + duokan-text-indent: 0; + font-family: "楷体"; + font-size: 0.7em; + color: #FFC; + margin: 0; +} + +/*版本说明页*/ +.ver { + font-family: "DK-CODE","DK-XIHEITI",细黑体,"xihei",sans-serif; + font-weight: bold; + font-size: 100%; + color: #000; + margin: 1em 0 1em 0; + text-align: center; +} + +.vertitle { + font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif; + font-size: 100%; + text-indent: 0em; + text-align: left; + duokan-text-indent: 0em; +} + +.vertxt { + font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif; + line-height: 100%; + font-size: 85%; + text-indent: 0em; + text-align: left; + duokan-text-indent: 0em; +} +.verchar { + font-family: "DK-KAITI","kt","楷体","楷体_gb2312"; + text-align: left; + text-indent: 1em; + duokan-text-indent: 1em; + margin-bottom: 1em; + margin-top: 1em; +} +.vernote { + font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif; + font-size: 75%; + color: #686d70; + text-indent: 0em; + text-align: left; + duokan-text-indent: 0em; + padding-bottom: 15px; +} + +.line { + border: dotted #A2906A; + border-width: 1px 0 0 0; +} + +.entry { + margin-left: 18px; + font-size: 83%; + color: #8fe0a3; + text-indent: 0em; + duokan-text-indent: 0em; +} +/*版权信息*/ +.vol { + text-indent: 0em; + text-align: center; + padding: 0.8em; + margin: 0 auto 3px auto; + color: #000; + font-family: "方正小标宋_GBK","DK-XIAOBIAOSONG"; + font-size: 130%; + text-shadow: none; +} + +.cp { + font-family: "DK-CODE","DK-XIHEITI",细黑体,"xihei",sans-serif; + color: #412938; + font-size: 70%; + text-align: left; + text-indent: 0em; + duokan-text-indent: 0em; +} + +.xchar { + font-family: "DK-KAITI","kt","楷体","楷体_gb2312"; + text-indent: 0em; + duokan-text-indent: 0em; +} +/*多看弹注*/ +sup img { + line-height: 100%; + width: auto; + height: 1.0em; + margin: 0em; + padding: 0em; + vertical-align: text-top; +} + +ol { + margin-bottom:0; + padding:0 auto; + list-style-type: decimal; +} +.hr { + width:50%; + margin:2em 0 0 0.5em; + padding:0; + height:2px; + background-color: #F3221D; +} + +.duokan-footnote-content{ + padding:0 auto; + text-align: left; +} + +.duokan-footnote-item { + font-family:"DK-XIHEITI",细黑体,"xihei",sans-serif; + text-align: left; + font-size: 80%; + line-height: 100%; + clear: both; + color:#000; + list-style-type:decimal; +} + +li.duokan-footnote-item a { + font-family:"DK-HEITI"; + text-align: left; +} +a{ + text-decoration: none; + color: #222; +} + +a:hover {background: #81caf9} +a:active {background: yellow} +.duokan-image-maintitle { + font-family:"DK-HEITI",黑体,"hei",sans-serif; + text-align: center; + text-indent: 0em; + duokan-text-indent: 0em; + font-size:90%; + color: #1F4150; + margin-top: 1em; +} + +.duokan-image-subtitle { + font-family:"DK-XIHEITI",细黑体,"xihei",sans-serif; + text-align: center; + text-indent: 0em; + duokan-text-indent: 0em; + font-size:70%; + color: #3A3348; + margin-top: 1em; +} \ No newline at end of file diff --git a/app/src/main/assets/help/ruleHelp.md b/app/src/main/assets/help/ruleHelp.md index 4d50dde6c..01eb44eba 100644 --- a/app/src/main/assets/help/ruleHelp.md +++ b/app/src/main/assets/help/ruleHelp.md @@ -11,6 +11,12 @@ : regex规则,不可省略,只可以用在书籍列表和目录列表 ``` +* 获取登录后的cookie +``` +java.getCookie("http://baidu.com", null) => userid=1234;pwd=adbcd +java.getCookie("http://baidu.com", "userid") => 1234 +``` + * 请求头,支持http代理,socks4 socks5代理设置 ``` socks5代理 @@ -39,6 +45,49 @@ cache 变量-缓存操作类,方法见 io.legado.app.help.CacheManager chapter 变量-当前目录类,方法见 io.legado.app.data.entities.BookChapter title 变量-当前标题,String src 内容,源码 +``` + +* url添加js参数,解析url时执行,可在访问url时处理url,例 +``` +https://www.baidu.com,{"js":"java.headerMap.put('xxx', 'yyy')"} +https://www.baidu.com,{"js":"java.url=java.url+'yyyy'"} +``` + +* 增加js方法,用于重定向拦截 + * `java.get(urlStr: String, headers: Map)` + * `java.post(urlStr: String, body: String, headers: Map)` +* 对于搜索重定向的源,可以使用此方法获得重定向后的url +``` +(()=>{ + if(page==1){ + let url='https://www.yooread.net/e/search/index.php,'+JSON.stringify({ + "method":"POST", + "body":"show=title&tempid=1&keyboard="+key + }); + return java.put('surl',String(java.connect(url).raw().request().url())); + } else { + return java.get('surl')+'&page='+(page-1) + } +})() +或者 +(()=>{ + let base='https://www.yooread.net/e/search/'; + if(page==1){ + let url=base+'index.php'; + let body='show=title&tempid=1&keyboard='+key; + return base+java.put('surl',java.post(url,body,{}).header("Location")); + } else { + return base+java.get('surl')+'&page='+(page-1); + } +})() +``` + +* 正文图片链接支持修改headers +``` +let options = { +"headers": {"User-Agent": "xxxx","Referrer":baseUrl,"Cookie":"aaa=vbbb;"} +}; +'' ``` ## 部分js对象属性说明 @@ -95,14 +144,16 @@ variable // 自定义书籍变量信息(用于书源规则检索书籍信息) ### 字体解析使用 > 使用方法,在正文替换规则中使用,原理根据f1字体的字形数据到f2中查找字形对应的编码 ``` -@js: -var b64=String(src).match(/ttf;base64,([^\)]+)/); -if (b64) { - var f1 = java.queryBase64TTF(b64[1]) - var f2 = java.queryTTF("/storage/emulated/0/Fonts/Source Han Sans CN Regular.ttf") - java.replaceFont(result, f1, f2) -}else{ - result -} + +(function(){ + var b64=String(src).match(/ttf;base64,([^\)]+)/); + if(b64){ + var f1 = java.queryBase64TTF(b64[1]); + var f2 = java.queryTTF("https://alanskycn.gitee.io/teachme/assets/font/Source Han Sans CN Regular.ttf"); + return java.replaceFont(result, f1, f2); + } + return result; +})() + ``` diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index 0daafa351..20e915987 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -18,6 +18,18 @@ * 添加书架文件夹分组样式,未完成 * viewPager2 3层嵌套有问题,书架换回viewPager +**2021/05/29** +* 谷歌版可使用外部epub模板 +* Asset文件夹下二级以内目录全文件读取,Asset->文件夹->文件 +* epub元数据修改,使修改字体只对正文生效 +* 修复epub模板文件的排序问题 +* epub可自定义模板,模板路径为书籍导出目录的Asset文件夹,[模板范例](https://wwa.lanzoux.com/ibjBspkn05i) +``` +Asset中里面必须有Text文件夹,Text文件夹里必须有chapter.html,否则导出正文会为空 +chapter.html的关键字有{title}、{content} +其他html文件的关键字有{name}、{author}、{intro}、{kind}、{wordCount} +``` + **2021/05/26** * 书签绑定书名与作者 * 修复详情页目录问题 diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index a7db60a2d..e76b28df3 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -38,9 +38,9 @@ object AppConst { val keyboardToolChars: List by lazy { arrayListOf( - "❓", "@css:", "", "{{}}", "&&", "%%", "||", "//", "$.", "@", - "\\", ":", "class", "id", "href", "textNodes", "ownText", "all", "html", - "[", "]", "<", ">", "##", "!", ".", "+", "-", "*", "=",",{\"webView\":true}" + "❓", "@css:", "", "{{}}", "##", "&&", "%%", "||", "//", "$.", + "@", ":", "class", "text", "href", "textNodes", "ownText", "all", "html", + "[", "]", "<", ">", "#", "!", ".", "+", "-", "*", "=", "{'webView': true}" ) } @@ -57,10 +57,12 @@ object AppConst { val urlOption: String by lazy { """ ,{ - "charset": "", - "method": "POST", - "body": "", - "headers": {"User-Agent": ""} + 'charset': '', + 'method': 'POST', + 'body': '', + 'headers': { + 'User-Agent': '' + } } """.trimIndent() } diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 99adf90b1..6379d4cc3 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -38,7 +38,7 @@ object BookHelp { } /** - * 清楚已删除书的缓存 + * 清除已删除书的缓存 */ fun clearRemovedCache() { Coroutine.async { diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index 43fcd60a9..a3698c76c 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -311,9 +311,9 @@ interface JsExtensions { * @param font2 正确的字体 */ fun replaceFont( - text: String, - font1: QueryTTF?, - font2: QueryTTF? + text: String, + font1: QueryTTF?, + font2: QueryTTF? ): String { if (font1 == null || font2 == null) return text val contentArray = text.toCharArray() @@ -346,7 +346,7 @@ interface JsExtensions { str: String, key: String, transformation: String, - iv: String = "" + iv: String ): ByteArray? { return EncoderUtils.decryptAES( @@ -369,7 +369,7 @@ interface JsExtensions { str: String, key: String, transformation: String, - iv: String = "" + iv: String ): String? { return aesDecodeToByteArray(str, key, transformation, iv)?.let { String(it) } } @@ -386,7 +386,7 @@ interface JsExtensions { str: String, key: String, transformation: String, - iv: String = "" + iv: String ): ByteArray? { return EncoderUtils.decryptBase64AES( data = str.encodeToByteArray(), @@ -408,7 +408,7 @@ interface JsExtensions { str: String, key: String, transformation: String, - iv: String = "" + iv: String ): String? { return aesBase64DecodeToByteArray(str, key, transformation, iv)?.let { String(it) } } @@ -422,7 +422,7 @@ interface JsExtensions { */ fun aesEncodeToByteArray( data: String, key: String, transformation: String, - iv: String = "" + iv: String ): ByteArray? { return EncoderUtils.encryptAES( data.encodeToByteArray(), @@ -441,7 +441,7 @@ interface JsExtensions { */ fun aesEncodeToString( data: String, key: String, transformation: String, - iv: String = "" + iv: String ): String? { return aesEncodeToByteArray(data, key, transformation, iv)?.let { String(it) } } @@ -455,7 +455,7 @@ interface JsExtensions { */ fun aesEncodeToBase64ByteArray( data: String, key: String, transformation: String, - iv: String = "" + iv: String ): ByteArray? { return EncoderUtils.encryptAES2Base64( data.encodeToByteArray(), @@ -474,7 +474,7 @@ interface JsExtensions { */ fun aesEncodeToBase64String( data: String, key: String, transformation: String, - iv: String = "" + iv: String ): String? { return aesEncodeToBase64ByteArray(data, key, transformation, iv)?.let { String(it) } } diff --git a/app/src/main/java/io/legado/app/model/Debug.kt b/app/src/main/java/io/legado/app/model/Debug.kt index d8e606b0f..dc6259cc4 100644 --- a/app/src/main/java/io/legado/app/model/Debug.kt +++ b/app/src/main/java/io/legado/app/model/Debug.kt @@ -187,7 +187,7 @@ object Debug { private fun infoDebug(scope: CoroutineScope, webBook: WebBook, book: Book) { if (book.tocUrl.isNotBlank()) { - log(debugSource, "目录url不为空,详情页已解析") + log(debugSource, "≡已获取目录链接,跳过详情页") log(debugSource, showTime = false) tocDebug(scope, webBook, book) return diff --git a/app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt index 06ae294b4..24bf4981e 100644 --- a/app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt @@ -190,12 +190,12 @@ object BookChapterList { chapterList.add(bookChapter) } } - Debug.log(bookSource.bookSourceUrl, "└解析目录列表完成", log) - Debug.log(bookSource.bookSourceUrl, "┌首章名称", log) + Debug.log(bookSource.bookSourceUrl, "└目录列表解析完成", log) + Debug.log(bookSource.bookSourceUrl, "┌获取首章名称", log) Debug.log(bookSource.bookSourceUrl, "└${chapterList[0].title}", log) - Debug.log(bookSource.bookSourceUrl, "┌首章链接", log) + Debug.log(bookSource.bookSourceUrl, "┌获取首章链接", log) Debug.log(bookSource.bookSourceUrl, "└${chapterList[0].url}", log) - Debug.log(bookSource.bookSourceUrl, "┌首章信息", log) + Debug.log(bookSource.bookSourceUrl, "┌获取首章信息", log) Debug.log(bookSource.bookSourceUrl, "└${chapterList[0].tag}", log) } return ChapterData(chapterList, nextUrlList) diff --git a/app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt b/app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt index fab7802b6..f89d997c3 100644 --- a/app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt @@ -23,6 +23,7 @@ import io.legado.app.utils.* import me.ag2s.epublib.domain.* import me.ag2s.epublib.epub.EpubWriter import me.ag2s.epublib.util.ResourceUtil +import splitties.init.appCtx import java.io.ByteArrayOutputStream import java.io.File import java.io.FileOutputStream @@ -35,11 +36,11 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { fun getExportFileName(book: Book): String { val jsStr = AppConfig.bookExportFileName if (jsStr.isNullOrBlank()) { - return "${book.name} by ${book.author}" + return "${book.name} 作者:${book.getRealAuthor()}" } val bindings = SimpleBindings() bindings["name"] = book.name - bindings["author"] = book.author + bindings["author"] = book.getRealAuthor() return AppConst.SCRIPT_ENGINE.eval(jsStr, bindings).toString() } @@ -122,11 +123,29 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { private fun getAllContents(book: Book, append: (text: String) -> Unit) { val useReplace = AppConfig.exportUseReplace val contentProcessor = ContentProcessor(book.name, book.origin) - append("${book.name}\n${context.getString(R.string.author_show, book.author)}") + append( + "${book.name}\n${ + context.getString( + R.string.author_show, + book.getRealAuthor() + ) + }\n${ + context.getString( + R.string.intro_show, + "\n" + HtmlFormatter.format(book.getDisplayIntro()) + ) + }" + ) appDb.bookChapterDao.getChapterList(book.bookUrl).forEach { chapter -> BookHelp.getContent(book, chapter).let { content -> val content1 = contentProcessor - .getContent(book, chapter.title, content ?: "null", false, useReplace) + .getContent( + book, + chapter.title.replace("\\r?\\n".toRegex(), " "), + content ?: "null", + false, + useReplace + ) .joinToString("\n") append.invoke("\n\n$content1") } @@ -138,9 +157,9 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { appDb.bookChapterDao.getChapterList(book.bookUrl).forEach { chapter -> BookHelp.getContent(book, chapter)?.let { content -> content.split("\n").forEachIndexed { index, text -> - val matches = AppPattern.imgPattern.toRegex().findAll(input = text) - matches.forEach { matchResult -> - matchResult.groupValues[1].let { + val matcher = AppPattern.imgPattern.matcher(text) + while (matcher.find()) { + matcher.group(1)?.let { val src = NetworkUtils.getAbsoluteURL(chapter.url, it) srcList.add(Triple(chapter.title, index, src)) } @@ -181,12 +200,11 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { setEpubMetadata(book, epubBook) //set cover setCover(book, epubBook) - //set css - setCSS(epubBook) - //设置正文 - setEpubContent(book, epubBook) + val contentModel = setAssets(doc, book, epubBook) + //设置正文 + setEpubContent(contentModel, book, epubBook) DocumentUtils.createFileIfNotExist(doc, filename)?.let { bookDoc -> context.contentResolver.openOutputStream(bookDoc.uri, "wa")?.use { bookOs -> EpubWriter().write(epubBook, bookOs) @@ -205,28 +223,144 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { //set cover setCover(book, epubBook) //set css - setCSS(epubBook) - + val contentModel = setAssets(book, epubBook) val bookPath = FileUtils.getPath(file, filename) val bookFile = FileUtils.createFileWithReplace(bookPath) //设置正文 - setEpubContent(book, epubBook) + setEpubContent(contentModel, book, epubBook) EpubWriter().write(epubBook, FileOutputStream(bookFile)) } - private fun setCSS(epubBook: EpubBook) { - //set css + private fun setAssets(doc: DocumentFile, book: Book, epubBook: EpubBook): String { + if(!AppConfig.isGooglePlay) return setAssets(book, epubBook) + + var contentModel = "" + DocumentUtils.getDirDocument(doc, "Asset").let { customPath -> + if (customPath == null) {//使用内置模板 + contentModel = setAssets(book, epubBook) + } else {//外部模板 + customPath.listFiles().forEach { folder -> + if (folder.isDirectory && folder.name == "Text") { + folder.listFiles().sortedWith { o1, o2 -> + val name1 = o1.name ?: "" + val name2 = o2.name ?: "" + name1.cnCompare(name2) + }.forEach { file -> + if (file.isFile) { + when { + //正文模板 + file.name.equals( + "chapter.html", + true + ) || file.name.equals("chapter.xhtml", true) -> { + contentModel = file.readText(context) ?: "" + } + //封面等其他模板 + true == file.name?.endsWith("html", true) -> { + epubBook.addSection( + FileUtils.getNameExcludeExtension( + file.name ?: "Cover.html" + ), + ResourceUtil.createPublicResource( + book.name, + book.getRealAuthor(), + book.getDisplayIntro(), + book.kind, + book.wordCount, + file.readText(context) ?: "", + "${folder.name}/${file.name}" + ) + ) + } + else -> { + //其他格式文件当做资源文件 + folder.listFiles().forEach { + if (it.isFile) + epubBook.resources.add( + Resource( + it.readBytes(context), + "${folder.name}/${it.name}" + ) + ) + } + } + } + } + } + } else if (folder.isDirectory) { + //资源文件 + folder.listFiles().forEach { + if (it.isFile) + epubBook.resources.add( + Resource( + it.readBytes(context), + "${folder.name}/${it.name}" + ) + ) + } + } else {//Asset下面的资源文件 + epubBook.resources.add( + Resource( + folder.readBytes(context), + "${folder.name}" + ) + ) + } + } + } + } + + return contentModel + } + + private fun setAssets(book: Book, epubBook: EpubBook): String { + epubBook.resources.add( + Resource( + appCtx.assets.open("epub/fonts.css").readBytes(), + "Styles/fonts.css" + ) + ) + epubBook.resources.add( + Resource( + appCtx.assets.open("epub/main.css").readBytes(), + "Styles/main.css" + ) + ) epubBook.resources.add( Resource( - "body,div{background:white;outline:none;width:100%;}h2{color:#005a9c;text-align:left;}p{text-indent:2em;text-align:justify;}img{display:inline-block;width:100%;height:auto;max-width: 100%;max-height:100%;}".encodeToByteArray(), - "css/style.css" + appCtx.assets.open("epub/logo.png").readBytes(), + "Images/logo.png" + ) + ) + epubBook.addSection( + context.getString(R.string.img_cover), + ResourceUtil.createPublicResource( + book.name, + book.getRealAuthor(), + book.getDisplayIntro(), + book.kind, + book.wordCount, + String(appCtx.assets.open("epub/cover.html").readBytes()), + "Text/cover.html" + ) + ) + epubBook.addSection( + context.getString(R.string.book_intro), + ResourceUtil.createPublicResource( + book.name, + book.getRealAuthor(), + book.getDisplayIntro(), + book.kind, + book.wordCount, + String(appCtx.assets.open("epub/intro.html").readBytes()), + "Text/intro.html" ) ) + return String(appCtx.assets.open("epub/chapter.html").readBytes()) } private fun setCover(book: Book, epubBook: EpubBook) { - Glide.with(context) .asBitmap() .load(book.getDisplayCover()) @@ -237,21 +371,19 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { val byteArray: ByteArray = stream.toByteArray() resource.recycle() stream.close() - epubBook.coverImage = Resource(byteArray, "cover.jpg") + epubBook.coverImage = Resource(byteArray, "Images/cover.jpg") } override fun onLoadCleared(placeholder: Drawable?) { - } - }) } - - private fun setEpubContent(book: Book, epubBook: EpubBook) { + private fun setEpubContent(contentModel: String, book: Book, epubBook: EpubBook) { + //正文 val useReplace = AppConfig.exportUseReplace val contentProcessor = ContentProcessor(book.name, book.origin) - appDb.bookChapterDao.getChapterList(book.bookUrl).forEach { chapter -> + appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter -> BookHelp.getContent(book, chapter).let { content -> var content1 = fixPic(epubBook, book, content ?: "null", chapter) content1 = contentProcessor @@ -259,23 +391,17 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { .joinToString("\n") epubBook.addSection( chapter.title, - ResourceUtil.createHTMLResource(chapter.title, content1) + ResourceUtil.createChapterResource( + chapter.title.replace("\uD83D\uDD12", ""), + content1, + contentModel, + "Text/chapter_${index}.html" + ) ) } } } - private fun setPic(src: String, book: Book, epubBook: EpubBook) { - - val href = "${MD5Utils.md5Encode16(src)}${BookHelp.getImageSuffix(src)}" - val vFile = BookHelp.getImage(book, src) - val fp = FileResourceProvider(vFile.parent) - if (vFile.exists()) { - val img = LazyResource(fp, href) - epubBook.resources.add(img) - } - } - private fun fixPic( epubBook: EpubBook, book: Book, @@ -285,19 +411,21 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { val data = StringBuilder("") content.split("\n").forEach { text -> var text1 = text - val matches = AppPattern.imgPattern.toRegex().findAll(input = text) - matches.forEach { matchResult -> - matchResult.groupValues[1].let { + val matcher = AppPattern.imgPattern.matcher(text) + while (matcher.find()) { + matcher.group(1)?.let { val src = NetworkUtils.getAbsoluteURL(chapter.url, it) - setPic(src, book, epubBook) - text1 = text1.replace( - src, - "${MD5Utils.md5Encode16(src)}${BookHelp.getImageSuffix(src)}" - ) - + val originalHref = "${MD5Utils.md5Encode16(src)}${BookHelp.getImageSuffix(src)}" + val href = "Images/${MD5Utils.md5Encode16(src)}.${BookHelp.getImageSuffix(src)}" + val vFile = BookHelp.getImage(book, src) + val fp = FileResourceProvider(vFile.parent) + if (vFile.exists()) { + val img = LazyResource(fp, href, originalHref) + epubBook.resources.add(img) + } + text1 = text1.replace(src, "../${href}") } } - data.append(text1).append("\n") } return data.toString() @@ -309,13 +437,11 @@ class CacheViewModel(application: Application) : BaseViewModel(application) { metadata.authors.add(Author(book.getRealAuthor()))//书籍的作者 metadata.language = "zh"//数据的语言 metadata.dates.add(Date())//数据的创建日期 - metadata.publishers.add("Legado APP")//数据的创建者 + metadata.publishers.add("Legado")//数据的创建者 metadata.descriptions.add(book.getDisplayIntro())//书籍的简介 //metadata.subjects.add("")//书籍的主题,在静读天下里面有使用这个分类书籍 epubBook.metadata = metadata } //////end of EPUB - - } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/HtmlFormatter.kt b/app/src/main/java/io/legado/app/utils/HtmlFormatter.kt index 21d45d62c..7d11df2b4 100644 --- a/app/src/main/java/io/legado/app/utils/HtmlFormatter.kt +++ b/app/src/main/java/io/legado/app/utils/HtmlFormatter.kt @@ -13,7 +13,7 @@ object HtmlFormatter { html ?: return "" return html.replace(wrapHtmlRegex, "\n") .replace(otherRegex, "") - .replace("^[\\n\\s]+".toRegex(), "  ") + .replace("^[\\n\\s]*".toRegex(), "  ") .replace("[\\n\\s]+$".toRegex(), "") .replace("\\s*\\n+\\s*".toRegex(), "\n  ") } diff --git a/build.gradle b/build.gradle index 894cbf12f..ae689e1a9 100644 --- a/build.gradle +++ b/build.gradle @@ -4,24 +4,22 @@ buildscript { ext.kotlin_version = '1.5.10' repositories { google() - maven { url 'https://maven.aliyun.com/repository/public/'} - maven { url "https://s3.amazonaws.com/fabric-artifacts/public" } - maven { url "https://maven.aliyun.com/repository/gradle-plugin" } - maven { url "https://plugins.gradle.org/m2/" } + maven { url 'https://maven.aliyun.com/repository/public' } + maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } + maven { url 'https://plugins.gradle.org/m2/' } } dependencies { classpath 'com.android.tools.build:gradle:4.2.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "de.timfreiheit.resourceplaceholders:placeholders:0.3" + classpath 'de.timfreiheit.resourceplaceholders:placeholders:0.3' } } allprojects { repositories { google() - maven { url 'https://maven.aliyun.com/repository/public/' } - maven { url "https://jitpack.io" } - maven { url "https://maven.google.com/" } + maven { url 'https://maven.aliyun.com/repository/public' } + maven { url 'https://jitpack.io' } } } diff --git a/epublib/src/main/java/me/ag2s/epublib/Constants.java b/epublib/src/main/java/me/ag2s/epublib/Constants.java index e26c56815..d9f873e41 100644 --- a/epublib/src/main/java/me/ag2s/epublib/Constants.java +++ b/epublib/src/main/java/me/ag2s/epublib/Constants.java @@ -7,6 +7,7 @@ public interface Constants { String DOCTYPE_XHTML = ""; String NAMESPACE_XHTML = "http://www.w3.org/1999/xhtml"; String EPUB_GENERATOR_NAME = "Ag2S EpubLib"; + String EPUB_DUOKAN_NAME = "DK-SONGTI"; char FRAGMENT_SEPARATOR_CHAR = '#'; String DEFAULT_TOC_ID = "toc"; } diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/LazyResource.java b/epublib/src/main/java/me/ag2s/epublib/domain/LazyResource.java index 1c833401c..a0faf070e 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/LazyResource.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/LazyResource.java @@ -28,6 +28,9 @@ public class LazyResource extends Resource { public LazyResource(LazyResourceProvider resourceProvider, String href) { this(resourceProvider, -1, href); } + public LazyResource(LazyResourceProvider resourceProvider, String href, String originalHref) { + this(resourceProvider, -1, href, originalHref); + } /** * Creates a Lazy resource, by not actually loading the data for this entry. @@ -39,11 +42,17 @@ public class LazyResource extends Resource { * @param href The resource's href within the epub. */ public LazyResource( - LazyResourceProvider resourceProvider, long size, String href) { + LazyResourceProvider resourceProvider, long size, String href) { super(null, null, href, MediaTypes.determineMediaType(href)); this.resourceProvider = resourceProvider; this.cachedSize = size; } + public LazyResource( + LazyResourceProvider resourceProvider, long size, String href, String originalHref) { + super(null, null, href, originalHref, MediaTypes.determineMediaType(href)); + this.resourceProvider = resourceProvider; + this.cachedSize = size; + } /** * Gets the contents of the Resource as an InputStream. diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/Resource.java b/epublib/src/main/java/me/ag2s/epublib/domain/Resource.java index 4820a7aff..2349c9e91 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/Resource.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/Resource.java @@ -120,6 +120,9 @@ public class Resource implements Serializable { public Resource(String id, byte[] data, String href, MediaType mediaType) { this(id, data, href, mediaType, Constants.CHARACTER_ENCODING); } + public Resource(String id, byte[] data, String href, String originalHref, MediaType mediaType) { + this(id, data, href, originalHref, mediaType, Constants.CHARACTER_ENCODING); + } /** @@ -141,6 +144,15 @@ public class Resource implements Serializable { this.inputEncoding = inputEncoding; this.data = data; } + public Resource(String id, byte[] data, String href, String originalHref, MediaType mediaType, + String inputEncoding) { + this.id = id; + this.href = href; + this.originalHref = originalHref; + this.mediaType = mediaType; + this.inputEncoding = inputEncoding; + this.data = data; + } /** * Gets the contents of the Resource as an InputStream. diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/Resources.java b/epublib/src/main/java/me/ag2s/epublib/domain/Resources.java index 7566f4f3a..27d512700 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/Resources.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/Resources.java @@ -193,9 +193,9 @@ public class Resources implements Serializable { private String createHref(MediaType mediaType, int counter) { if (MediaTypes.isBitmapImage(mediaType)) { - return "image_" + counter + mediaType.getDefaultExtension(); + return IMAGE_PREFIX + counter + mediaType.getDefaultExtension(); } else { - return "item_" + counter + mediaType.getDefaultExtension(); + return ITEM_PREFIX + counter + mediaType.getDefaultExtension(); } } diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentBase.java b/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentBase.java index c7ce55b78..a172ce32d 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentBase.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentBase.java @@ -9,7 +9,7 @@ package me.ag2s.epublib.epub; */ public class PackageDocumentBase { - public static final String BOOK_ID_ID = "BookId"; + public static final String BOOK_ID_ID = "duokan-book-id"; public static final String NAMESPACE_OPF = "http://www.idpf.org/2007/opf"; public static final String NAMESPACE_DUBLIN_CORE = "http://purl.org/dc/elements/1.1/"; public static final String PREFIX_DUBLIN_CORE = "dc"; @@ -92,5 +92,6 @@ public class PackageDocumentBase { String reference_cover = "cover"; String no = "no"; String generator = "generator"; + String duokan = "duokan-body-font"; } } \ No newline at end of file diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataWriter.java b/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataWriter.java index f4811a6c7..fc758bc03 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataWriter.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataWriter.java @@ -120,6 +120,15 @@ public class PackageDocumentMetadataWriter extends PackageDocumentBase { Constants.EPUB_GENERATOR_NAME); serializer.endTag(NAMESPACE_OPF, OPFTags.meta); + // write duokan + serializer.startTag(NAMESPACE_OPF, OPFTags.meta); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.name, + OPFValues.duokan); + serializer + .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.content, + Constants.EPUB_DUOKAN_NAME); + serializer.endTag(NAMESPACE_OPF, OPFTags.meta); + serializer.endTag(NAMESPACE_OPF, OPFTags.metadata); } diff --git a/epublib/src/main/java/me/ag2s/epublib/util/ResourceUtil.java b/epublib/src/main/java/me/ag2s/epublib/util/ResourceUtil.java index 9b8f7896e..f270bdbb3 100644 --- a/epublib/src/main/java/me/ag2s/epublib/util/ResourceUtil.java +++ b/epublib/src/main/java/me/ag2s/epublib/util/ResourceUtil.java @@ -30,60 +30,31 @@ public class ResourceUtil { /** * 快速创建HTML类型的Resource * - * @param title 章节的标题 - * @param string 章节的正文 + * @param title 章节的标题 + * @param txt 章节的正文 + * @param model html模板 * @return 返回Resource */ - public static Resource createHTMLResource(String title, String string) { - String html = createHtml(title, string); - MediaType mediaTypeProperty = MediaTypes.XHTML; - byte[] data = html.getBytes(); - return new Resource(data, mediaTypeProperty); - } - - /** - * 快速创建HTML类型的Resource - * - * @param title 章节的标题 - * @param string 章节的正文 - * @param href Resource的href - * @return 返回Resource - */ - - @SuppressWarnings("unused") - public static Resource createHTMLResource(String title, String string, String href) { - String html = createHtml(title, string); - MediaType mediaTypeProperty = MediaTypes.XHTML; - byte[] data = html.getBytes(); - return new Resource(null, data, href, mediaTypeProperty); - } - - @SuppressWarnings("unused") - private static String createHtml(String title, String txt) { - StringBuilder body = new StringBuilder(); - for (String s : txt.split("\\r?\\n")) { - //移除多余的开头结尾的空白字符,节省epub的体积 - s = StringUtil.FixTrim(s); - if (s.length() != 0) { - if (s.contains("").append(s).append(""); - } else { - body.append("

").append(s).append("

"); - } - - } - + public static Resource createChapterResource(String title, String txt, String model, String href) { + if (title.contains("\n")) { + title = "" + title.replaceFirst("\\s*\\n\\s*", "
"); + } else { + title = title.replaceFirst("\\s+", "
"); + if (title.contains("")) + title = "" + title; } + String html = model.replaceAll("\\{title\\}", title) + .replaceAll("\\{content\\}", StringUtil.formatHtml(txt)); + return new Resource(html.getBytes(), href); + } - return "" + - "" + - "" + title + "" + - "" + - "" + - "

" + title + "

" + - body + - ""; + public static Resource createPublicResource(String name, String author, String intro, String kind, String wordCount, String model, String href) { + String html = model.replaceAll("\\{name\\}", name) + .replaceAll("\\{author\\}", author) + .replaceAll("\\{kind\\}", kind) + .replaceAll("\\{wordCount\\}", wordCount) + .replaceAll("\\{intro\\}", StringUtil.formatHtml(intro)); + return new Resource(html.getBytes(), href); } /** diff --git a/epublib/src/main/java/me/ag2s/epublib/util/StringUtil.java b/epublib/src/main/java/me/ag2s/epublib/util/StringUtil.java index 929278b98..f3c0a6058 100644 --- a/epublib/src/main/java/me/ag2s/epublib/util/StringUtil.java +++ b/epublib/src/main/java/me/ag2s/epublib/util/StringUtil.java @@ -273,25 +273,19 @@ public class StringUtil { } return text.substring(cPos + 1); } - // 移除字符串首尾空字符的高效方法(利用ASCII值判断,包括全角空格) - public static String FixTrim(String s) { - if (s == null || s.isEmpty()) { - return ""; - } - int start = 0; - int len = s.length(); - int end = len - 1; - while (start < end && (s.charAt(start) <= 0x20 || s.charAt(start) == ' ')) { - ++start; - } - while (start < end && (s.charAt(end) <= 0x20 || s.charAt(end) == ' ')) { - --end; - } - if (end < len) { - ++end; - } - return (start > 0 || end < len) ? s.substring(start, end) : s; + public static String formatHtml(String text) { + StringBuilder body = new StringBuilder(); + for (String s : text.split("\\r?\\n")) { + s = s.replaceAll("^\\s+|\\s+$", ""); + if (s.length() > 0) { + if (s.toLowerCase().contains("]+)/?>", "
")); + } else { + body.append("

").append(s).append("

"); + } + } + } + return body.toString(); } - }