├── .gitattributes
├── .idea
├── .gitignore
├── deployment.xml
└── webServers.xml
├── main.go
├── yournovel
├── static
│ ├── img
│ │ ├── lcxs.jpg
│ │ ├── login.png
│ │ ├── bookMark.png
│ │ ├── favicon.png
│ │ ├── github.png
│ │ ├── read_bg.png
│ │ ├── lcxs_show.jpg
│ │ ├── logo_home.png
│ │ ├── basic_bg.0.4.png
│ │ ├── left_bar_flag.png
│ │ ├── logo_search.png
│ │ ├── read_content.png
│ │ ├── theme_1_bg.0.4.png
│ │ ├── theme_2_bg.0.4.png
│ │ ├── theme_3_bg.0.4.png
│ │ ├── theme_5_bg.0.4.png
│ │ ├── body_base_bg.0.4.png
│ │ ├── body_theme1_bg.0.4.png
│ │ ├── body_theme2_bg.0.4.png
│ │ ├── body_theme3_bg.0.4.png
│ │ └── body_theme5_bg.0.4.png
│ ├── js
│ │ ├── books.js
│ │ ├── bookmarks.js
│ │ ├── list.js
│ │ ├── register.js
│ │ ├── main.js
│ │ ├── theme.js
│ │ └── content.js
│ └── css
│ │ └── web
│ │ ├── result.css
│ │ ├── register.css
│ │ ├── index.css
│ │ ├── main.css
│ │ ├── content.css
│ │ └── chapter.css
├── service
│ ├── searchengine
│ │ ├── baiduengine_test.go
│ │ └── baiduengine.go
│ └── novel
│ │ ├── searchchapter_test.go
│ │ ├── searchchapter.go
│ │ └── searchcontent.go
├── dao
│ ├── user
│ │ └── user.go
│ └── novel
│ │ └── novel.go
├── conf
│ ├── server.go
│ └── rule.go
├── http
│ ├── Index.go
│ ├── chapter.go
│ ├── content.go
│ ├── http.go
│ ├── search.go
│ └── content_test.go
├── fetcher
│ └── fetcher.go
├── view
│ └── web
│ │ ├── search
│ │ ├── search_bar.html
│ │ └── search_index.html
│ │ ├── index
│ │ └── index.html
│ │ ├── category
│ │ └── chapter_index.html
│ │ ├── content
│ │ └── content_index.html
│ │ └── common
│ │ └── main.html
├── middleware
│ └── middleware.go
├── model
│ └── search.go
├── tool
│ └── utils.go
└── db
│ └── redis
│ ├── redisclient_test.go
│ └── redisclient.go
├── .gitignore
├── README.md
├── go.mod
└── LICENSE
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.js linguist-language=Go
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Default ignored files
3 | /workspace.xml
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "yournovel/yournovel/http"
4 |
5 | func main() {
6 | http.Init()
7 | }
8 |
--------------------------------------------------------------------------------
/yournovel/static/img/lcxs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/lcxs.jpg
--------------------------------------------------------------------------------
/yournovel/static/img/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/login.png
--------------------------------------------------------------------------------
/yournovel/static/img/bookMark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/bookMark.png
--------------------------------------------------------------------------------
/yournovel/static/img/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/favicon.png
--------------------------------------------------------------------------------
/yournovel/static/img/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/github.png
--------------------------------------------------------------------------------
/yournovel/static/img/read_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/read_bg.png
--------------------------------------------------------------------------------
/yournovel/static/img/lcxs_show.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/lcxs_show.jpg
--------------------------------------------------------------------------------
/yournovel/static/img/logo_home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/logo_home.png
--------------------------------------------------------------------------------
/yournovel/static/img/basic_bg.0.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/basic_bg.0.4.png
--------------------------------------------------------------------------------
/yournovel/static/img/left_bar_flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/left_bar_flag.png
--------------------------------------------------------------------------------
/yournovel/static/img/logo_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/logo_search.png
--------------------------------------------------------------------------------
/yournovel/static/img/read_content.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/read_content.png
--------------------------------------------------------------------------------
/yournovel/static/img/theme_1_bg.0.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/theme_1_bg.0.4.png
--------------------------------------------------------------------------------
/yournovel/static/img/theme_2_bg.0.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/theme_2_bg.0.4.png
--------------------------------------------------------------------------------
/yournovel/static/img/theme_3_bg.0.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/theme_3_bg.0.4.png
--------------------------------------------------------------------------------
/yournovel/static/img/theme_5_bg.0.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/theme_5_bg.0.4.png
--------------------------------------------------------------------------------
/yournovel/static/img/body_base_bg.0.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/body_base_bg.0.4.png
--------------------------------------------------------------------------------
/yournovel/static/img/body_theme1_bg.0.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/body_theme1_bg.0.4.png
--------------------------------------------------------------------------------
/yournovel/static/img/body_theme2_bg.0.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/body_theme2_bg.0.4.png
--------------------------------------------------------------------------------
/yournovel/static/img/body_theme3_bg.0.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/body_theme3_bg.0.4.png
--------------------------------------------------------------------------------
/yournovel/static/img/body_theme5_bg.0.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DemonFengYuXiang/YourNovel/HEAD/yournovel/static/img/body_theme5_bg.0.4.png
--------------------------------------------------------------------------------
/yournovel/service/searchengine/baiduengine_test.go:
--------------------------------------------------------------------------------
1 | package searchengine
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestEngineRune(t *testing.T) {
8 |
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/yournovel/dao/user/user.go:
--------------------------------------------------------------------------------
1 | package user
2 |
3 | import (
4 | "fmt"
5 | "yournovel/yournovel/conf"
6 | )
7 |
8 | func TestUser() {
9 |
10 | fmt.Println(conf.Config["host"])
11 | }
12 |
--------------------------------------------------------------------------------
/yournovel/conf/server.go:
--------------------------------------------------------------------------------
1 | package conf
2 |
3 | const (
4 | Host = "0.0.0.0"
5 | Port = 8079
6 | Scheme = "http://"
7 |
8 | RedisAddr = "ip:port"
9 | RedisPassword = "password"
10 | RedisDb = 0
11 | )
12 |
--------------------------------------------------------------------------------
/yournovel/dao/novel/novel.go:
--------------------------------------------------------------------------------
1 | package novel
2 |
3 | import (
4 | "fmt"
5 | "yournovel/yournovel/conf"
6 | )
7 |
8 | func TestNovel() {
9 | fmt.Println(conf.Config["host"])
10 | conf.Config["host"] = "10.1.1.1"
11 | }
12 |
--------------------------------------------------------------------------------
/yournovel/http/Index.go:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "net/http"
6 | )
7 |
8 | // 首页
9 | func home(c *gin.Context) {
10 | c.HTML(http.StatusOK, "index.html", gin.H{
11 | "head": "index_head",
12 | })
13 | }
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, build with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 | go.sum
14 | .idea/misc.xml
15 | .idea/modules.xml
16 | .idea/vcs.xml
17 | yournovel.iml
18 |
--------------------------------------------------------------------------------
/yournovel/fetcher/fetcher.go:
--------------------------------------------------------------------------------
1 | package fetcher
2 |
3 | import (
4 | "github.com/gocolly/colly"
5 | "github.com/gocolly/colly/extensions"
6 | )
7 |
8 | func NewNovelConnector() *colly.Collector {
9 | c := colly.NewCollector(
10 | colly.DetectCharset(),
11 | )
12 | extensions.RandomUserAgent(c)
13 | extensions.Referer(c)
14 |
15 | return c
16 | }
17 |
--------------------------------------------------------------------------------
/.idea/deployment.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/yournovel/service/novel/searchchapter_test.go:
--------------------------------------------------------------------------------
1 | package novel
2 |
3 | import (
4 | "github.com/gocolly/colly"
5 | "github.com/gocolly/colly/extensions"
6 | "testing"
7 | )
8 |
9 | func TestSearchChapter(t *testing.T) {
10 |
11 | c := colly.NewCollector(
12 | colly.DetectCharset(),
13 | )
14 | extensions.RandomUserAgent(c)
15 | extensions.Referer(c)
16 |
17 | c.OnHTML("#at", func(element *colly.HTMLElement) {
18 | })
19 |
20 | c.Visit("https://www.x23us.com/html/64/64889/")
21 | }
22 |
--------------------------------------------------------------------------------
/.idea/webServers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
--------------------------------------------------------------------------------
/yournovel/view/web/search/search_bar.html:
--------------------------------------------------------------------------------
1 | {{ define "search_bar" }}
2 |
16 | {{ end }}
--------------------------------------------------------------------------------
/yournovel/middleware/middleware.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "errors"
5 | "github.com/gin-gonic/gin"
6 | "net/http"
7 | )
8 |
9 | type MyMiddlewareOption struct {
10 | IsAuth bool
11 | }
12 |
13 | func RequestMiddlewareWrapper(f func(ctx *gin.Context), option MyMiddlewareOption) func(ctx *gin.Context) {
14 | return func(ctx *gin.Context) {
15 | if option.IsAuth {
16 | err := auth(ctx)
17 | if err != nil {
18 | ctx.JSON(http.StatusInternalServerError, gin.H{
19 | "code": 0,
20 | "msg": "鉴权失败",
21 | })
22 | return
23 | }
24 | }
25 | f(ctx)
26 | }
27 | }
28 |
29 | // 鉴权
30 | func auth(ctx *gin.Context) error {
31 | return errors.New("鉴权失败")
32 | }
33 |
--------------------------------------------------------------------------------
/yournovel/http/chapter.go:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "net/http"
6 | "yournovel/yournovel/service/novel"
7 | "yournovel/yournovel/tool"
8 | )
9 |
10 | func novelChapter(c *gin.Context) {
11 |
12 | webSiteUrl, exist := c.GetQuery("url")
13 | if !exist {
14 | tool.ErrorResponse(c, "源网址不存在", webSiteUrl)
15 | return
16 | }
17 | novelName, exist := c.GetQuery("novel_name")
18 | if !exist {
19 | c.Redirect(http.StatusMovedPermanently, webSiteUrl)
20 | return
21 | }
22 |
23 | novelChapter, err := novel.SearchChapterOfNovel(webSiteUrl, novelName)
24 | if err != nil {
25 | //c.Redirect(http.StatusMovedPermanently, webSiteUrl)
26 | return
27 | }
28 |
29 | c.HTML(http.StatusOK, "chapter_index.html", gin.H{
30 | "chapter": novelChapter,
31 | "head": "chapter_head",
32 | } )
33 | }
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # YourNovel - 开源小说搜索引擎
2 |
3 | ## 起源
4 |
5 | 项目起源于Github上另外一个类似的小说搜索引擎项目 https://github.com/howie6879/owllook, 该项目给小说爱好者带来极大的福利(无广告、清爽的界面)。但是, 该项目作者貌似马上要关闭网站了, 想想自己手上有多余的服务器并且刚学完Golang, 马上行动起来使用Golang花了几天的时间开发出了这个项目。
6 |
7 | **注意: 本项目前端代码以及服务端的一些思想借鉴了owllook项目,后期可能会根据自己喜好进行修改,因此,若你看见类似的东西请不要惊讶**
8 |
9 | ## 要求
10 |
11 | - Go 1.12+
12 | - Go Module 开启
13 | - Redis
14 |
15 | ## 安装以及使用
16 |
17 | - git clone https://github.com/DemonFengYuXiang/YourNovel.git
18 |
19 | - `mv YourNovel yournovel`
20 |
21 | - `vim yournovel/yournovel/conf/server.go` 填写Reids地址以及密码等信息
22 |
23 | - `cd yournovel`
24 |
25 | - ` go run main.go`
26 |
27 | ## Reference
28 |
29 | YourNovel使用了以下第三方包:
30 |
31 | - gin
32 | - go-redis/redis
33 | - colly
34 | - goquery
35 | ....
36 |
37 | YourNovel借鉴项目:
38 |
39 | [owllook](https://github.com/howie6879/owllook)
40 |
41 |
--------------------------------------------------------------------------------
/yournovel/model/search.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import "html/template"
4 |
5 | type SearchResult struct {
6 | Href string `json:"href"`
7 | Title string `json:"title"`
8 | IsParse int `json:"is_parse"`
9 | Host string `json:"host"`
10 | }
11 |
12 | type NovelChapter struct {
13 | Name string `json:"name"`
14 | OriginUrl string `json:"origin_url"`
15 | Content template.HTML `json:"content"`
16 | LinkPrefix string `json:"link_prefix"`
17 | Domain string `json:"domain"`
18 | }
19 |
20 | type NovelContent struct {
21 | NovelName string `json:"novel_name"`
22 | Title string `json:"title"`
23 | ContentUrl string `json:"content_url"`
24 | Content template.HTML `json:"content"`
25 | PreChapter string `json:"pre_chapter"`
26 | NextChapter string `json:"next_chapter"`
27 | }
28 |
--------------------------------------------------------------------------------
/yournovel/tool/utils.go:
--------------------------------------------------------------------------------
1 | package tool
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "net/http"
6 | "net/url"
7 | "strconv"
8 | "yournovel/yournovel/conf"
9 | )
10 |
11 | func GetHost() string {
12 | host := conf.Host+":"+ strconv.Itoa(conf.Port)
13 | return host
14 | }
15 |
16 | func SuccessResponse(ctx *gin.Context, msg string, data interface{}) {
17 | ctx.JSON(http.StatusOK, gin.H{
18 | "code": 1,
19 | "msg": msg,
20 | "data": data,
21 | })
22 | }
23 |
24 | func ErrorResponse(ctx *gin.Context, msg string, data interface{}) {
25 | ctx.JSON(http.StatusOK, gin.H{
26 | "code": 0,
27 | "msg": msg,
28 | "data": data,
29 | })
30 | }
31 |
32 | func UrlJoin(href, base string) string {
33 | uri, err := url.Parse(href)
34 | if err != nil {
35 | return " "
36 | }
37 | baseUrl, err := url.Parse(base)
38 | if err != nil {
39 | return " "
40 | }
41 |
42 | return baseUrl.ResolveReference(uri).String()
43 | }
44 |
45 |
46 |
--------------------------------------------------------------------------------
/yournovel/static/js/books.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by howie on 24/04/2017.
3 | */
4 |
5 | $(document).ready(function () {
6 | $(".del-book").click(function () {
7 | var msg = "您真的确定要删除吗?请确认!";
8 | if (confirm(msg)) {
9 | var book_url = $(this).find('a.book_url').attr("data-value");
10 | var del_pd = {"book_url": book_url};
11 | var del_object = $(this).parent();
12 | $.ajax({
13 | type: "post",
14 | contentType: "application/json",
15 | url: "/operate/delete_book",
16 | data: del_pd,
17 | dataType: 'json',
18 | success: function (data) {
19 | if (data.status == 1) {
20 | del_object.remove();
21 | }
22 | if (data.status == -1) {
23 | alert('您还没有登录');
24 | }
25 | }
26 | });
27 | }
28 | });
29 | });
--------------------------------------------------------------------------------
/yournovel/static/js/bookmarks.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by howie on 24/04/2017.
3 | */
4 |
5 | $(document).ready(function () {
6 | $(".del-bookmark").click(function () {
7 | var msg = "您真的确定要删除吗?请确认!";
8 | if (confirm(msg)) {
9 | var bookmarkurl = $(this).find('a.bookmark_url').attr("data-value");
10 | var del_bm_pd = {"bookmarkurl": bookmarkurl};
11 | var del_bm_object = $(this).parent();
12 | $.ajax({
13 | type: "post",
14 | contentType: "application/json",
15 | url: "/operate/delete_bookmark",
16 | data: del_bm_pd,
17 | dataType: 'json',
18 | success: function (data) {
19 | if (data.status == 1) {
20 | del_bm_object.remove();
21 | }
22 | if (data.status == -1) {
23 | alert('您还没有登录');
24 | }
25 | }
26 | });
27 | }
28 | });
29 | });
--------------------------------------------------------------------------------
/yournovel/db/redis/redisclient_test.go:
--------------------------------------------------------------------------------
1 | package redis
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | "yournovel/yournovel/model"
7 | )
8 |
9 | func TestRedisClinet(t *testing.T) {
10 |
11 | InitRedisClient()
12 |
13 | searchResult := &model.SearchResult{}
14 | searchResult.Title = "帝霸"
15 | searchResult.Host = "hao123.com"
16 | searchResult.IsParse = 1
17 | searchResult.Href = "http://www.baidu.com"
18 |
19 | searchResult2 := &model.SearchResult{}
20 | searchResult2.Title = "帝霸"
21 | searchResult2.Host = "hao123.com"
22 | searchResult2.IsParse = 1
23 | searchResult2.Href = "http://www.baidu.com"
24 |
25 | searchResults := []*model.SearchResult{
26 | searchResult,
27 | searchResult2,
28 | }
29 |
30 | err := RedisConnector.SaveSearchResultByNovelName("帝霸", searchResults)
31 | if err != nil {
32 | t.Errorf("%s", err)
33 | }
34 |
35 | results, err := RedisConnector.SearchNovelByNovelName("帝霸")
36 | if err != nil {
37 | t.Errorf("%s", err)
38 | }
39 |
40 | for _,result := range results {
41 | fmt.Println(result.Href)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/yournovel/view/web/index/index.html:
--------------------------------------------------------------------------------
1 | {{ template "header" .}}
2 |
3 | {{ define "index_head" }}
4 |
YourNovel-基于Go的开源简洁免费小说网站无广告无弹窗
5 | {{ end }}
6 |
7 |
8 |
16 |
17 |
18 |

19 |
20 |
26 |
27 |
28 | {{ template "footer" .}}
29 |
--------------------------------------------------------------------------------
/yournovel/static/js/list.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by howie on 21/02/2017.
3 | */
4 | $(document).ready(function () {
5 | var link_prefix = $("#link_prefix").val();
6 | var chapter_url = $("#url").val();
7 | var novels_name = $("#novels_name").val();
8 | var domain = $("#domain").val();
9 | $(".container a").each(function () {
10 | var url = $(this).attr('href');
11 | url = url.trimLeft("/");
12 | if (typeof(url) != "undefined") {
13 | if (url.indexOf("yournovel") < 0) {
14 | var name = $(this).text();
15 | var prefix = '';
16 | if (link_prefix == '-1') {
17 | prefix = chapter_url;
18 | }else if (link_prefix == '1') {
19 | prefix = '';
20 | }else if (link_prefix == '0') {
21 | prefix = domain;
22 | }
23 | show_url = "content?content_url=" + prefix + '/' + url + "&content_title=" + name + "&chapter_url=" + chapter_url + "&novel_name=" + novels_name;
24 | $(this).attr('href', show_url);
25 | $(this).attr('target', '_blank');
26 | }
27 | }
28 | });
29 | });
--------------------------------------------------------------------------------
/yournovel/http/content.go:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin"
6 | "net/http"
7 | "yournovel/yournovel/service/novel"
8 | )
9 |
10 | func novelContent(c *gin.Context) {
11 |
12 | chapterUrl, exist := c.GetQuery("chapter_url")
13 | if !exist {
14 | c.Redirect(http.StatusMovedPermanently, "/")
15 | return
16 | }
17 |
18 | contentUrl, exist := c.GetQuery("content_url")
19 | if !exist {
20 | c.Redirect(http.StatusMovedPermanently, chapterUrl)
21 | return
22 | }
23 | novelName, exist := c.GetQuery("novel_name")
24 | if !exist {
25 | c.Redirect(http.StatusMovedPermanently, chapterUrl)
26 | return
27 | }
28 |
29 | contentTitle, exist := c.GetQuery("content_title")
30 | if !exist {
31 | c.Redirect(http.StatusMovedPermanently, chapterUrl)
32 | return
33 | }
34 |
35 | content, err := novel.SearchContentOfNovel(contentUrl)
36 | if err != nil {
37 | fmt.Println(content)
38 | //c.Redirect(http.StatusMovedPermanently, chapterUrl)
39 | return
40 | }
41 | content.NovelName = novelName
42 | content.ContentUrl = contentUrl
43 |
44 | c.HTML(http.StatusOK, "content_index.html", gin.H{
45 | "content": content,
46 | "chapter_url": chapterUrl,
47 | "novel_name": novelName,
48 | "content_title": contentTitle,
49 | "head": "content_head",
50 | })
51 | }
52 |
--------------------------------------------------------------------------------
/yournovel/service/novel/searchchapter.go:
--------------------------------------------------------------------------------
1 | package novel
2 |
3 | import (
4 | "fmt"
5 | "github.com/gocolly/colly"
6 | "html/template"
7 | "net/url"
8 | "yournovel/yournovel/conf"
9 | "yournovel/yournovel/fetcher"
10 | "yournovel/yournovel/model"
11 | )
12 |
13 | func SearchChapterOfNovel(novelUrl string, novelName string) (*model.NovelChapter, error) {
14 | c := fetcher.NewNovelConnector()
15 |
16 | var novelChapter model.NovelChapter
17 | requestURI, err := url.ParseRequestURI(novelUrl)
18 | if err != nil {
19 | return &novelChapter, err
20 | }
21 |
22 | host := requestURI.Host
23 | chapterSelector,ok := conf.RuleConfig.Rule[host]["chapter_selector"].(string)
24 | if !ok {
25 | return &novelChapter, err
26 | }
27 |
28 | c.OnHTML(chapterSelector, func(element *colly.HTMLElement) {
29 | html,_ := element.DOM.Parent().Html()
30 | if err != nil {
31 | return
32 | }
33 |
34 | novelChapter.Content = template.HTML(html)
35 | novelChapter.Name = novelName
36 | novelChapter.OriginUrl = novelUrl
37 | novelChapter.LinkPrefix = conf.RuleConfig.Rule[host]["link_prefix"].(string)
38 | novelChapter.Domain = fmt.Sprintf("%s://%s", requestURI.Scheme, requestURI.Host)
39 | })
40 |
41 | err = c.Visit(novelUrl)
42 | if err != nil {
43 | return &novelChapter, err
44 | }
45 |
46 | return &novelChapter, nil
47 | }
48 |
--------------------------------------------------------------------------------
/yournovel/http/http.go:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "yournovel/yournovel/conf"
6 | "yournovel/yournovel/db/redis"
7 | "yournovel/yournovel/middleware"
8 | "yournovel/yournovel/tool"
9 | )
10 |
11 | func Init() {
12 | g := gin.Default()
13 | initRouter(g)
14 | err := g.Run(tool.GetHost())
15 | if err != nil {
16 | panic(err)
17 | }
18 | }
19 |
20 | // 初始化路由
21 | func initRouter(engine *gin.Engine) {
22 | conf.InitConfig()
23 | redis.InitRedisClient()
24 | initConfig(engine)
25 | initGetRouter(engine)
26 | initPostRouter(engine)
27 | }
28 |
29 | func initConfig(engine *gin.Engine) {
30 | engine.LoadHTMLGlob("./yournovel/view/**/**/*")
31 | engine.Static("/assets", "./yournovel/static")
32 | }
33 |
34 | // 初始化Get路由
35 | func initGetRouter(engine *gin.Engine) {
36 | engine.GET("/", middleware.RequestMiddlewareWrapper(home, middleware.MyMiddlewareOption{
37 | IsAuth: false,
38 | }))
39 |
40 | engine.GET("/chapter", middleware.RequestMiddlewareWrapper(novelChapter, middleware.MyMiddlewareOption{
41 | IsAuth: false,
42 | }))
43 |
44 | engine.GET("/search", middleware.RequestMiddlewareWrapper(novelSearch, middleware.MyMiddlewareOption{
45 | IsAuth: false,
46 | }))
47 |
48 | engine.GET("/content", middleware.RequestMiddlewareWrapper(novelContent, middleware.MyMiddlewareOption{
49 | IsAuth: false,
50 | }))
51 | }
52 |
53 | // 初始化Post路由
54 | func initPostRouter(engine *gin.Engine) {
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/yournovel/view/web/category/chapter_index.html:
--------------------------------------------------------------------------------
1 | {{ template "header" .}}
2 |
3 | {{ define "chapter_head" }}
4 | {{ .chapter.Name }}-目录
5 |
6 | {{ end }}
7 |
8 |
9 |
10 | ×
11 |
12 |
13 | 注意!页面内容来自{{ .chapter.OriginUrl }},本站不储存任何内容,为了更好的阅读体验进行在线解析,若有广告出现,请及时反馈。若您觉得侵犯了您的利益,请通知我们进行删除,然后访问
14 | 原网页
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | {{ .chapter.Content }}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | {{ template "footer" . }}
35 |
36 |
--------------------------------------------------------------------------------
/yournovel/view/web/content/content_index.html:
--------------------------------------------------------------------------------
1 | {{ template "header" .}}
2 |
3 | {{ define "content_head" }}
4 | {{ .content.Title }}-小说内容
5 |
6 |
12 | {{ end }}
13 |
14 |
22 |
23 |
24 |
25 |
{{ .content.Title }}
26 |
27 |
28 | {{ .content.Content }}
29 |
30 |
31 |
32 |
43 |
44 | {{ template "footer" . }}
45 |
46 |
47 |
--------------------------------------------------------------------------------
/yournovel/static/css/web/result.css:
--------------------------------------------------------------------------------
1 | .navbar {
2 | border-radius: 0 !important;
3 | min-height: 65px !important;
4 | }
5 |
6 | .result {
7 | margin-right: 0 !important;
8 | padding-right: 15px;
9 | padding-left: 7%;
10 | margin-bottom: 60px;
11 | }
12 |
13 | .result > p {
14 | padding-left: 4%;
15 | }
16 |
17 | .form-control {
18 | width: 90% !important;
19 | height: 35px !important;
20 | line-height: 35px !important;
21 | margin-top: 20px;
22 | border-radius: 0 !important;
23 | }
24 |
25 | div.item > li {
26 | margin-top: 15px;
27 | }
28 |
29 | div.item > li > a {
30 | color: #38556A;
31 | font-size: 16px;
32 | }
33 |
34 | .netloc {
35 | display: block;
36 | color: #006621;
37 | }
38 |
39 | .result_item {
40 | width: 35em;
41 | height: 95px;
42 | overflow: hidden;
43 | text-overflow: ellipsis;
44 | white-space: nowrap;
45 | padding-left: 5%;
46 | font-size: 15px;
47 | }
48 |
49 | .tags {
50 | position: relative;
51 | margin-top: 5px;
52 | }
53 |
54 | .parse-label {
55 | position: absolute;
56 | right: 0;
57 | }
58 |
59 | .login {
60 | min-height: 65px;
61 | text-align: center;
62 | }
63 |
64 | .login > a {
65 | margin-top: 15px;
66 | }
67 |
68 | .modal-dialog .form-control {
69 | margin-top: 0 !important;
70 | }
71 |
72 | @media (max-width: 767px) {
73 | .result {
74 | padding-right: 0 !important;
75 | }
76 |
77 | .show-result {
78 | margin-bottom: 40px;
79 | }
80 |
81 | .col-xs-12 {
82 | padding-left: 0 !important;
83 | }
84 |
85 | .move {
86 | display: none;
87 | }
88 |
89 | .show-result .tags .label {
90 | right: -10px !important;
91 | }
92 |
93 | .netloc i {
94 | font-size: 13px;
95 | }
96 | }
--------------------------------------------------------------------------------
/yournovel/db/redis/redisclient.go:
--------------------------------------------------------------------------------
1 | package redis
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "github.com/go-redis/redis"
7 | jsoniter "github.com/json-iterator/go"
8 | "time"
9 | "yournovel/yournovel/conf"
10 | "yournovel/yournovel/model"
11 | )
12 |
13 | type RedisClient struct {
14 | client *redis.Client
15 | }
16 |
17 | var RedisConnector *RedisClient
18 |
19 | func InitRedisClient() {
20 | client := redis.NewClient(&redis.Options{
21 | Addr: conf.RedisAddr,
22 | Password: conf.RedisPassword,
23 | DB: conf.RedisDb,
24 | })
25 |
26 | RedisConnector = &RedisClient{
27 | client: client,
28 | }
29 |
30 | pong, err := client.Ping().Result()
31 | if err != nil {
32 | fmt.Println(err)
33 | }
34 | fmt.Println(pong)
35 | return
36 | }
37 |
38 | // 根据小说名称将搜索结果保存至Redis中
39 | func (connector *RedisClient) SaveSearchResultByNovelName(novelName string, searchResult []*model.SearchResult) error {
40 | if searchResult == nil {
41 | return errors.New(fmt.Sprintf("novel:%s searchResult failure", novelName))
42 | }
43 |
44 | searchJson, err := jsoniter.ConfigFastest.MarshalToString(searchResult)
45 | if err != nil {
46 | return err
47 | }
48 |
49 | err = connector.client.Set(novelName, searchJson, 24 * time.Hour).Err()
50 | if err != nil {
51 | return err
52 | }
53 |
54 | return nil
55 | }
56 |
57 | // 从Redis中获取搜索小说
58 | func (connector *RedisClient) SearchNovelByNovelName(novelName string) ([]*model.SearchResult, error) {
59 | var searchResult []*model.SearchResult
60 | searchJson, err := connector.client.Get(novelName).Result()
61 | if err == redis.Nil {
62 | return searchResult, errors.New(fmt.Sprintf("Redis Error: %s not exists??", novelName))
63 | }
64 |
65 | err = jsoniter.ConfigFastest.UnmarshalFromString(searchJson, &searchResult)
66 | if err != nil {
67 | return nil, err
68 | }
69 |
70 | return searchResult, nil
71 | }
72 |
--------------------------------------------------------------------------------
/yournovel/static/css/web/register.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #f1f1f1 !important;
3 | }
4 |
5 | .logo {
6 | margin: 5% auto;
7 | }
8 |
9 | .register {
10 | width: 40%;
11 | height: 100%;
12 | background-color: white;
13 | margin-top: 4%;
14 | padding: 2rem 4rem;
15 | box-shadow: 0 0 8px rgba(0, 0, 0, .1);
16 | }
17 |
18 | .title {
19 | text-align: center;
20 | font-family: -apple-system, SF UI Display, Arial, PingFang SC, Hiragino Sans GB, Microsoft YaHei, WenQuanYi Micro Hei, sans-serif;
21 | font-weight: 700;
22 | font-size: 3rem;
23 | margin: 2rem 0;
24 | }
25 |
26 | .input-group {
27 | position: relative;
28 | width: 100%;
29 | }
30 |
31 | .sign {
32 | padding: 4px 12px 4px 25px !important;
33 | font-family: -apple-system, SF UI Text, Arial, PingFang SC, Hiragino Sans GB, Microsoft YaHei, WenQuanYi Micro Hei, sans-serif;
34 | height: 50px !important;
35 | font-size: 14px;
36 | border: 1px solid #c8c8c8;
37 | border-bottom: none;
38 | width: 100%;
39 | background-color: #f1f1f1;
40 | outline: none
41 | }
42 |
43 | .sign-last {
44 | border-bottom: 1px solid #c8c8c8;
45 | margin-bottom: 2rem;
46 | }
47 |
48 | .icon {
49 | position: absolute !important;
50 | top: 17px !important;
51 | left: 8px;
52 | color: #969696;
53 | }
54 |
55 | .submitBtn {
56 | width: 100%;
57 | margin-bottom: 3rem !important;
58 | padding: 1rem 0 !important;
59 | }
60 |
61 | .errorInfo {
62 | color: red;
63 | text-align: center;
64 | }
65 |
66 | .errorHidden0, .errorHidden1, .errorHidden2, .errorHidden3 {
67 | display: none;
68 | }
69 |
70 | @media (max-width: 960px) {
71 | .register {
72 | width: 100%;
73 | margin-top: -6%;
74 | }
75 | }
76 |
77 | @media (min-width: 1680px) {
78 | .register {
79 | margin-top: 20%;
80 | }
81 | }
--------------------------------------------------------------------------------
/yournovel/http/search.go:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin"
6 | "net/http"
7 | "sync"
8 | "time"
9 | "yournovel/yournovel/conf"
10 | "yournovel/yournovel/db/redis"
11 | "yournovel/yournovel/model"
12 | "yournovel/yournovel/service/searchengine"
13 | "yournovel/yournovel/tool"
14 | )
15 |
16 | type EngineSearch interface {
17 | EngineRun(string, *sync.WaitGroup)
18 | }
19 |
20 | // 小说搜索
21 | func novelSearch(c *gin.Context) {
22 | wd, exist := c.GetQuery("wd")
23 | if !exist || len(wd) == 0 {
24 | c.Redirect(http.StatusMovedPermanently, conf.Scheme + tool.GetHost() + "/")
25 | return
26 | }
27 |
28 | start := time.Now().UnixNano() / 1e6
29 | results := startEngine(wd)
30 | end := time.Now().UnixNano() / 1e6
31 |
32 | elapsedTime := (end - start) / 1e3
33 | searchCount := len(results)
34 | c.HTML(http.StatusOK, "search_index.html", gin.H{
35 | "list": results,
36 | "novelName": wd,
37 | "elapsedTime": elapsedTime,
38 | "count": searchCount,
39 | "head": "search_head",
40 | })
41 | }
42 |
43 | // 开始引擎搜索
44 | func startEngine(novelName string) []*model.SearchResult {
45 |
46 | results, err := redis.RedisConnector.SearchNovelByNovelName(novelName)
47 | if err == nil {
48 | return results
49 | }
50 |
51 | group := sync.WaitGroup{}
52 | results = make([]*model.SearchResult, 0)
53 | for _,engine := range conf.RuleConfig.Engines {
54 | var searchEngine EngineSearch
55 | group.Add(1)
56 | switch engine {
57 | case "baidu":
58 | searchEngine = searchengine.NewBaiDuSearchEngine(func(result *model.SearchResult) {
59 | results = append(results, result)
60 | })
61 | }
62 |
63 | if searchEngine != nil {
64 | go searchEngine.EngineRun(novelName, &group)
65 | }
66 | }
67 | group.Wait()
68 | if len(results) > 0 {
69 | err = redis.RedisConnector.SaveSearchResultByNovelName(novelName, results)
70 | if err != nil {
71 | fmt.Printf("Redis Save Failure %s", err)
72 | }
73 | }
74 |
75 | return results
76 | }
77 |
--------------------------------------------------------------------------------
/yournovel/view/web/search/search_index.html:
--------------------------------------------------------------------------------
1 | {{ template "header" .}}
2 |
3 | {{ define "search_head" }}
4 | {{ .novelName }}-搜索结果
5 |
6 |
13 | {{ end }}
14 | {{ $novelName := .novelName }}
15 | {{ template "search_bar" .}}
16 |
17 |
18 |
19 |
找到 {{ .count }} 条结果(用时{{ .elapsedTime }}s)
20 |
21 | {{ range .list }}
22 |
23 |
24 | {{ .Title }}
25 |
26 |
{{ .Host }}
27 |
查看源网址
28 | {{ if .IsParse }}
29 |
已解析
30 | {{ else }}
31 |
未解析
32 | {{ end }}
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | {{ end }}
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | {{ template "footer" .}}
54 |
--------------------------------------------------------------------------------
/yournovel/static/css/web/index.css:
--------------------------------------------------------------------------------
1 | div.search {
2 | width: 100%;
3 | text-align: center;
4 | height: 30px;
5 | line-height: 30px;
6 |
7 | }
8 |
9 | div.logo {
10 | padding-top: 10%;
11 | }
12 |
13 | form.home_search {
14 | height: 120px;
15 | margin-top: 55px;
16 | }
17 |
18 | div.search > .form-control {
19 | width: 55%;
20 | height: 40px;
21 | line-height: 40px;
22 | }
23 |
24 | div.search > .btn-default {
25 | width: 134px;
26 | height: 35px;
27 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#f1f1f1));
28 | background-image: -webkit-linear-gradient(top, #f5f5f5, #f1f1f1);
29 | -webkit-border-radius: 2px;
30 | -webkit-user-select: none;
31 | background-color: #f2f2f2;
32 | border: 1px solid #f2f2f2;
33 | border-radius: 2px;
34 | color: #757575;
35 | cursor: default;
36 | font-size: 13px;
37 | font-weight: bold;
38 | margin: 30px 4px;
39 | min-width: 54px;
40 | padding: 0 12px;
41 | text-align: center;
42 | }
43 |
44 | div.search > .btn-default:hover {
45 | border: 1px solid #c8c8c8;
46 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#f3f3f3));
47 | background-image: -webkit-linear-gradient(top, #ffffff, #f4f4f4);
48 | background-color: #ffffff;
49 | color: #474747;
50 | }
51 |
52 | .login > .pull-right {
53 | position: absolute;
54 | right: 0;
55 | top: 5px;
56 | border: 1px solid #4285f4;
57 | font-weight: bold;
58 | outline: none;
59 | background: #4285f4;
60 | background: -webkit-linear-gradient(top, #4387fd, #4683ea);
61 | }
62 |
63 | div.owl_search_ranking {
64 | margin-top: 5%;
65 | width: 55%;
66 | }
67 |
68 | div.owl_search_ranking span {
69 | display: inline-block;
70 | font-size: 12px;
71 | padding: .3em .6em .3em;
72 | margin-bottom: 2px;
73 | }
74 |
75 | @media (max-width: 767px) {
76 | .logo {
77 | padding-top: 28% !important;
78 | }
79 |
80 | .logo img {
81 | width: 100px;
82 | height: 45px;
83 | }
84 |
85 | div.owl_search_ranking {
86 | display: none;
87 | }
88 | }
89 |
90 | @media (min-width: 992px) {
91 |
92 | }
93 |
94 | @media (min-width: 1680px) {
95 | .logo {
96 | padding-top: 20% !important;
97 | }
98 | }
--------------------------------------------------------------------------------
/yournovel/view/web/common/main.html:
--------------------------------------------------------------------------------
1 | {{ define "header" }}
2 |
3 |
4 |
5 |
6 |
7 | {{ if eq .head "index_head" }}
8 | {{ template "index_head" .}}
9 | {{ else if eq .head "search_head" }}
10 | {{ template "search_head" .}}
11 | {{ else if eq .head "chapter_head" }}
12 | {{ template "chapter_head" .}}
13 | {{ else if eq .head "content_head" }}
14 | {{ template "content_head" .}}
15 | {{ end }}
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
35 |
36 |
37 | {{ end }}}
38 | {{ define "footer" }}
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | {{ end }}}
47 |
--------------------------------------------------------------------------------
/yournovel/static/js/register.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by howie on 14/03/2017.
3 | */
4 | $(function () {
5 | $(".submitBtn").click(function () {
6 | var nickname = $("[name='nickname']").val();
7 | var email = $("[name='email']").val();
8 | var answer = $("[name='answer']").val();
9 | var password = $("[name='password']").val();
10 | var email_reg = /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/;
11 | var str_email = email_reg.test(email);
12 | $("#errorInfo0").addClass("errorHidden0");
13 | $("#errorInfo1").addClass("errorHidden1");
14 | $("#errorInfo2").addClass("errorHidden2");
15 | $("#errorInfo3").addClass("errorHidden3");
16 | if (str_email) {
17 | if (password == "" || password != $("[name='password2']").val()) {
18 | $(".errorInfo").removeClass("errorHidden1");
19 | }
20 | else if (password.length < 6 || nickname.length <= 2) {
21 | $(".errorInfo").removeClass("errorHidden0");
22 | }
23 | else if (nickname == "" || email == "" || answer == "") {
24 | $(".errorInfo").removeClass("errorHidden2");
25 | }
26 | else {
27 | register_pd = {
28 | 'user': nickname,
29 | 'pwd': password,
30 | 'email': email,
31 | 'answer': answer
32 | };
33 | $.ajax({
34 | type: "post",
35 | contentType: "application/json",
36 | url: "/operate/register",
37 | data: register_pd,
38 | dataType: 'json',
39 | success: function (data) {
40 | if (data.status == 1) {
41 | window.location.href = '/';
42 | }
43 | if (data.status == -1) {
44 | alert('用户名已存在 换个更好的名字吧');
45 | }
46 | if (data.status == -2) {
47 | alert('回答错了^_^');
48 | }
49 | if (data.status == 0) {
50 | alert('注册失败');
51 | }
52 | }
53 | });
54 | }
55 | } else {
56 | $(".errorInfo").removeClass("errorHidden3");
57 | }
58 | });
59 | });
--------------------------------------------------------------------------------
/yournovel/service/searchengine/baiduengine.go:
--------------------------------------------------------------------------------
1 | package searchengine
2 |
3 | import (
4 | "fmt"
5 | "github.com/gocolly/colly"
6 | "github.com/gocolly/colly/extensions"
7 | "net/url"
8 | "strings"
9 | "sync"
10 | "yournovel/yournovel/conf"
11 | "yournovel/yournovel/model"
12 | )
13 |
14 | type BaiDuSearchEngine struct {
15 | parseRule string
16 | searchRule string
17 | domain string
18 | parseResultFunc func(searchResult *model.SearchResult)
19 | }
20 |
21 | func NewBaiDuSearchEngine(parseResultFunc func(result *model.SearchResult)) *BaiDuSearchEngine {
22 | return &BaiDuSearchEngine{
23 | parseRule: "#content_left h3.t a",
24 | searchRule: "intitle:%s 小说 阅读",
25 | domain: "http://www.baidu.com/s?wd=%s&ie=utf-8&rn=15&vf_bl=1",
26 | parseResultFunc: parseResultFunc,
27 | }
28 | }
29 |
30 | func (engine *BaiDuSearchEngine) EngineRun(novelName string, group *sync.WaitGroup) {
31 | defer group.Done()
32 | searchKey := url.QueryEscape(fmt.Sprintf(engine.searchRule, novelName))
33 | requestUrl := fmt.Sprintf(engine.domain, searchKey)
34 |
35 | c := colly.NewCollector()
36 | extensions.RandomUserAgent(c)
37 | extensions.Referer(c)
38 |
39 | c.OnHTML(engine.parseRule, func(element *colly.HTMLElement) {
40 | group.Add(1)
41 | go engine.extractData(element, group)
42 | })
43 |
44 | err := c.Visit(requestUrl)
45 | if err != nil {
46 | fmt.Println(err)
47 | }
48 | }
49 |
50 | func (engine *BaiDuSearchEngine) extractData(element *colly.HTMLElement, group *sync.WaitGroup) {
51 | defer group.Done()
52 | href := element.Attr("href")
53 | title := element.Text
54 |
55 | c := colly.NewCollector()
56 | extensions.RandomUserAgent(c)
57 | extensions.Referer(c)
58 |
59 | c.OnResponse(func(response *colly.Response) {
60 | realUrl := response.Request.URL.String()
61 | isContain := strings.Contains(realUrl, "baidu")
62 | if isContain {
63 | return
64 | }
65 |
66 | host := response.Request.URL.Host
67 | _,ok := conf.RuleConfig.IgnoreDomain[host]
68 | if ok {
69 | return
70 | }
71 |
72 | isParse := engine.CheckIsParse(host)
73 | result := &model.SearchResult{Href:realUrl, Title:title, IsParse:isParse, Host:host}
74 | engine.parseResultFunc(result)
75 | })
76 |
77 | err := c.Visit(href)
78 | if err != nil {
79 | fmt.Println(err)
80 | }
81 | }
82 |
83 | func (engine *BaiDuSearchEngine) CheckIsParse(host string) int {
84 | isParse := 0
85 | for key := range conf.RuleConfig.Rule {
86 | if host == key {
87 | isParse = 1
88 | break
89 | }
90 | }
91 | return isParse
92 | }
93 |
--------------------------------------------------------------------------------
/yournovel/http/content_test.go:
--------------------------------------------------------------------------------
1 | package http
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "github.com/PuerkitoBio/goquery"
7 | "github.com/gocolly/colly"
8 | "regexp"
9 | "strings"
10 | "testing"
11 | "yournovel/yournovel/tool"
12 | )
13 |
14 | func TestNextChapter(t *testing.T) {
15 |
16 | c := colly.NewCollector(
17 | colly.DetectCharset(),
18 | )
19 |
20 | html := ""
21 | c.OnResponse(func(response *colly.Response) {
22 | html = string(response.Body)
23 | })
24 |
25 | c.Visit("https://www.qb5200.tw/xiaoshuo/40/40994/13951060.html")
26 |
27 | html = strings.ReplaceAll(html, "<<", "")
28 | html = strings.ReplaceAll(html, ">>", "")
29 |
30 | // 参考https://greasyfork.org/zh-CN/scripts/292-my-novel-reader
31 | next_reg := `(.*[第上前下后][一]?[0-9]{0,6}?[页张个篇章节步].*?)`
32 | judge_reg := `[第上前下后][一]?[0-9]{0,6}?[页张个篇章节步]`
33 |
34 | re := regexp.MustCompile(next_reg)
35 | allFind := re.FindAll([]byte(html), -1)
36 | allByte := bytes.Join(allFind, []byte("\n"))
37 | reader := bytes.NewReader(allByte)
38 | doc,_ := goquery.NewDocumentFromReader(reader)
39 |
40 | judgeRe := regexp.MustCompile(judge_reg)
41 |
42 | doc.Find("a").Each(func(i int, selection *goquery.Selection) {
43 | text := selection.Text()
44 | text = strings.ReplaceAll(text, " ", "")
45 | isNext := judgeRe.MatchString(text)
46 | if isNext {
47 | href,exist := selection.Attr("href")
48 | if !exist {
49 | return
50 | }
51 |
52 | url := tool.UrlJoin(href, "http://www.hao123.com")
53 | fmt.Println(url)
54 | }
55 | })
56 | }
57 |
58 | func TestTtile(t *testing.T) {
59 |
60 | c := colly.NewCollector(
61 | colly.DetectCharset(),
62 | )
63 |
64 | html := ""
65 | c.OnResponse(func(response *colly.Response) {
66 | html = string(response.Body)
67 | })
68 |
69 | c.Visit("https://www.qb5200.tw/xiaoshuo/40/40994/13951060.html")
70 |
71 | titleReg := `(第?\s*[一二两三四五六七八九十○零百千万亿0-91234567890]{1,6}\s*[章回卷节折篇幕集]\s*.*?)[_,-]`
72 | re := regexp.MustCompile(titleReg)
73 | titleRes := re.FindAllString(html, -1)
74 | title := ""
75 | reader := strings.NewReader(html)
76 | doc, _ := goquery.NewDocumentFromReader(reader)
77 | if titleRes != nil {
78 | title = titleRes[1]
79 | }else {
80 | doc.Find("h1").Each(func(i int, selection *goquery.Selection) {
81 | if i == 0 {
82 | title = selection.Text()
83 | }
84 | return
85 | })
86 | }
87 |
88 | if len(title) <= 0 {
89 | doc.Find("title").Each(func(i int, selection *goquery.Selection) {
90 | if i == 0 {
91 | title = selection.Text()
92 | }
93 | return
94 | })
95 | }
96 |
97 | fmt.Println(title)
98 | }
99 |
100 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module yournovel
2 |
3 | go 1.12
4 |
5 | require (
6 | github.com/PuerkitoBio/goquery v1.5.0
7 | github.com/antchfx/htmlquery v1.0.0 // indirect
8 | github.com/antchfx/xmlquery v1.0.0 // indirect
9 | github.com/antchfx/xpath v1.0.0 // indirect
10 | github.com/gin-gonic/gin v1.4.0
11 | github.com/go-redis/redis v6.15.2+incompatible
12 | github.com/gobwas/glob v0.2.3 // indirect
13 | github.com/gocolly/colly v1.2.0
14 | github.com/golang/protobuf v1.3.2 // indirect
15 | github.com/json-iterator/go v1.1.7
16 | github.com/kennygrant/sanitize v1.2.4 // indirect
17 | github.com/kr/pretty v0.1.0 // indirect
18 | github.com/onsi/ginkgo v1.10.1 // indirect
19 | github.com/onsi/gomega v1.7.0 // indirect
20 | github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect
21 | github.com/temoto/robotstxt v1.1.1 // indirect
22 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859
23 | golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 // indirect
24 | golang.org/x/text v0.3.2
25 | google.golang.org/appengine v1.6.1 // indirect
26 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
27 | gopkg.in/olivere/elastic.v5 v5.0.82
28 | )
29 |
30 | replace (
31 | cloud.google.com/go => github.com/googleapis/google-cloud-go v0.44.3
32 | cloud.google.com/go/datastore => github.com/googleapis/google-cloud-go/datastore v1.0.0
33 | github.com/coreos/etcd => github.com/etcd-io/etcd v3.3.15+incompatible
34 | go.etcd.io/bbolt => github.com/etcd-io/bbolt v1.3.3
35 | golang.org/x/crypto => github.com/golang/crypto v0.0.0-20190829043050-9756ffdc2472
36 | golang.org/x/exp => github.com/golang/exp v0.0.0-20190829153037-c13cbed26979
37 | golang.org/x/image => github.com/golang/image v0.0.0-20190829233526-b3c06291d021
38 | golang.org/x/lint => github.com/golang/lint v0.0.0-20190409202823-959b441ac422
39 | golang.org/x/mobile => github.com/golang/mobile v0.0.0-20190826170111-cafc553e1ac5
40 |
41 | golang.org/x/mod => github.com/golang/mod v0.1.0
42 | golang.org/x/net => github.com/golang/net v0.0.0-20190827160401-ba9fcec4b297
43 | golang.org/x/oauth2 => github.com/golang/oauth2 v0.0.0-20190604053449-0f29369cfe45
44 | golang.org/x/sync => github.com/golang/sync v0.0.0-20190423024810-112230192c58
45 | golang.org/x/sys => github.com/golang/sys v0.0.0-20190829204830-5fe476d8906b
46 | golang.org/x/time => github.com/golang/time v0.0.0-20190308202827-9d24e82272b4
47 | golang.org/x/tools => github.com/golang/tools v0.0.0-20190829210313-340205e581e5
48 | golang.org/x/xerrors => github.com/golang/xerrors v0.0.0-20190717185122-a985d3407aa7
49 | google.golang.org/api => github.com/googleapis/google-api-go-client v0.9.0
50 | google.golang.org/appengine => github.com/golang/appengine v1.6.2
51 | google.golang.org/genproto => github.com/googleapis/go-genproto v0.0.0-20190819201941-24fa4b261c55
52 | google.golang.org/grpc => github.com/grpc/grpc-go v1.23.0
53 | sigs.k8s.io/yaml => github.com/kubernetes-sigs/yaml v1.1.0
54 | )
55 |
--------------------------------------------------------------------------------
/yournovel/service/novel/searchcontent.go:
--------------------------------------------------------------------------------
1 | package novel
2 |
3 | import (
4 | "bytes"
5 | "github.com/PuerkitoBio/goquery"
6 | "github.com/gocolly/colly"
7 | "html/template"
8 | "net/url"
9 | "regexp"
10 | "strings"
11 | "yournovel/yournovel/conf"
12 | "yournovel/yournovel/fetcher"
13 | "yournovel/yournovel/model"
14 | "yournovel/yournovel/tool"
15 | )
16 |
17 | func SearchContentOfNovel(contentUrl string) (*model.NovelContent, error) {
18 | c := fetcher.NewNovelConnector()
19 | var novelContent model.NovelContent
20 |
21 | requestURI, err := url.ParseRequestURI(contentUrl)
22 | if err != nil {
23 | return &novelContent, err
24 | }
25 |
26 | host := requestURI.Host
27 | contentSelector,ok := conf.RuleConfig.Rule[host]["content_selector"].(string)
28 | if !ok {
29 | return &novelContent, err
30 | }
31 |
32 | c.OnResponse(func(response *colly.Response) {
33 | webHtml := string(response.Body)
34 | chapterUrls := getPreChapterAndNextChapterFromHtml(webHtml, contentUrl)
35 | novelContent.PreChapter = chapterUrls[0]
36 | novelContent.NextChapter = chapterUrls[1]
37 |
38 | title := getTitleFromHtml(webHtml)
39 | novelContent.Title = title
40 | })
41 |
42 | c.OnHTML(contentSelector, func(element *colly.HTMLElement) {
43 | html,err := element.DOM.Html()
44 | if err != nil {
45 | return
46 | }
47 | novelContent.Content = template.HTML(html)
48 | })
49 |
50 | err = c.Visit(contentUrl)
51 | if err != nil {
52 | return &novelContent, err
53 | }
54 |
55 | return &novelContent, nil
56 | }
57 |
58 | // 从HTML文件中获得上一页以及下一页
59 | func getPreChapterAndNextChapterFromHtml(html string, url string) []string {
60 | html = strings.ReplaceAll(html, "<<", "")
61 | html = strings.ReplaceAll(html, ">>", "")
62 |
63 | // 参考https://greasyfork.org/zh-CN/scripts/292-my-novel-reader
64 | next_reg := `(.*[第上前下后][一]?[0-9]{0,6}?[页张个篇章节步].*?)`
65 | judge_reg := `[第上前下后][一]?[0-9]{0,6}?[页张个篇章节步]`
66 |
67 | re := regexp.MustCompile(next_reg)
68 | allFind := re.FindAll([]byte(html), -1)
69 | allByte := bytes.Join(allFind, []byte("\n"))
70 | reader := bytes.NewReader(allByte)
71 | doc,_ := goquery.NewDocumentFromReader(reader)
72 |
73 | judgeRe := regexp.MustCompile(judge_reg)
74 |
75 | chapterUrls := make([]string, 0, 2)
76 | doc.Find("a").Each(func(i int, selection *goquery.Selection) {
77 | text := selection.Text()
78 | text = strings.ReplaceAll(text, " ", "")
79 | isNext := judgeRe.MatchString(text)
80 | if isNext {
81 | href,exist := selection.Attr("href")
82 | if !exist {
83 | return
84 | }
85 |
86 | chapterUrl := tool.UrlJoin(href, url)
87 | chapterUrls = append(chapterUrls, chapterUrl)
88 | }
89 | })
90 | return chapterUrls
91 | }
92 |
93 | func getTitleFromHtml(html string) string {
94 | titleReg := `(第?\s*[一二两三四五六七八九十○零百千万亿0-91234567890]{1,6}\s*[章回卷节折篇幕集]\s*.*?)[_,-]`
95 | re := regexp.MustCompile(titleReg)
96 | titleRes := re.FindAllString(html, 0)
97 | title := ""
98 | reader := strings.NewReader(html)
99 | doc, _ := goquery.NewDocumentFromReader(reader)
100 | if titleRes != nil {
101 | title = titleRes[0]
102 | }else {
103 | doc.Find("h1").Each(func(i int, selection *goquery.Selection) {
104 | if i == 0 {
105 | title = selection.Text()
106 | }
107 | return
108 | })
109 | }
110 |
111 | if len(title) <= 0 {
112 | doc.Find("title").Each(func(i int, selection *goquery.Selection) {
113 | if i == 0 {
114 | title = selection.Text()
115 | }
116 | return
117 | })
118 | }
119 |
120 | return title
121 | }
122 |
123 |
--------------------------------------------------------------------------------
/yournovel/static/css/web/main.css:
--------------------------------------------------------------------------------
1 | /*style for login*/
2 | .header {
3 | width: 100%;
4 | height: 70px;
5 | }
6 |
7 | .header > li {
8 | list-style: none;
9 | }
10 |
11 | .header .pull-right {
12 | margin-top: 15px;
13 | margin-right: 25px;
14 | }
15 |
16 | .header .dropdown-menu > li > a {
17 | padding: 2px 10px !important;
18 | }
19 |
20 | .header .dropdown-menu .glyphicon {
21 | top: 2px !important;
22 | }
23 |
24 | .header .dropdown-menu {
25 | min-width: 120px !important;
26 | }
27 |
28 | .header span.personal-basic {
29 | margin-left: 10px;
30 | }
31 |
32 | /*style for footer*/
33 | div.footer > .navbar {
34 | min-height: 40px !important;
35 | margin-top: 40px;
36 | margin-bottom: 0 !important;
37 | }
38 |
39 | .message > .right {
40 | float: left;
41 | position: absolute;
42 | right: 5%;
43 | }
44 |
45 | .message > .left {
46 | float: left;
47 | position: absolute;
48 | left: 2%;
49 | }
50 |
51 | .message > .right > span, .message > .left > span {
52 | text-align: center !important;
53 | line-height: 40px !important;
54 | height: 40px;
55 | }
56 |
57 | .right > span > a, .message > .left > span > a {
58 | color: #666;
59 | margin-left: 25px;
60 | }
61 |
62 | .donate {
63 | width: 60%;
64 | margin-top: 5%;
65 | margin-left: 20%;
66 | }
67 |
68 | .donate_lists {
69 | width: 60%;
70 | margin-top: 5%;
71 | margin-left: 20%;
72 | margin-bottom: 80px;
73 | }
74 |
75 | .alert {
76 | margin-bottom: 0 !important;
77 | }
78 |
79 | .move {
80 | position: fixed;
81 | bottom: 60px;
82 | right: 5px;
83 | border: 1px solid #dcdcdc;
84 | border-radius: 5px;
85 | }
86 |
87 | .move > .move_up, .move > .move_down {
88 | width: 48px;
89 | height: 48px;
90 | line-height: 40px;
91 | border: 1px solid #dcdcdc;
92 | background-color: #fff;
93 | transition: .1s ease-in;
94 | -webkit-transition: .1s ease-in;
95 | -moz-transition: .1s ease-in;
96 | -o-transition: .1s ease-in;
97 | -ms-transition: .1s ease-in;
98 | cursor: pointer;
99 | }
100 |
101 | .move_up > span, .move_down > span {
102 | width: 45px;
103 | height: 43px;
104 | line-height: 43px;
105 | text-align: center;
106 | font-size: 20px;
107 | color: rgba(72, 70, 70, 0.71);
108 | }
109 |
110 | .move > .move_up:hover, .move > .move_down:hover {
111 | background-color: #f9f9f9;
112 | }
113 |
114 | .move > .move_up > span:hover, .move > .move_down > span:hover {
115 | color: #434343;
116 | }
117 |
118 | .modal-dialog {
119 | margin-top: 15% !important;
120 | }
121 |
122 | .modal-dialog .modal-content {
123 | width: 420px;
124 | height: 250px;
125 | margin-left: auto;
126 | margin-right: auto;
127 | }
128 |
129 | @media (max-width: 1024px) {
130 | .right > span > a {
131 | margin-left: 5px !important;
132 | font-size: 12px;
133 | }
134 |
135 | .modal-dialog .modal-content {
136 | width: 80%;
137 | min-width: 265px;
138 | height: 260px;
139 | margin-left: auto;
140 | margin-right: auto;
141 | }
142 |
143 | label {
144 | padding-top: 8px !important;
145 | }
146 |
147 | .navbar-header {
148 | display: none !important;
149 | }
150 |
151 | .login > a {
152 | margin-top: 20px !important;
153 | }
154 |
155 | .header .pull-right {
156 | margin-top: 17px !important;
157 | }
158 |
159 | /*登陆后排版*/
160 | .header li.pull-right {
161 | margin-right: 0 !important;
162 | }
163 | }
--------------------------------------------------------------------------------
/yournovel/static/css/web/content.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: url(../img/read_bg.png) #ede7da !important;
3 | color: #333 !important;
4 | font-family: "Microsoft YaHei" !important;
5 | }
6 |
7 | .navbar {
8 | background: rgb(242, 238, 230) !important;
9 | }
10 |
11 | .search {
12 | width: 200px;
13 | height: 50px;
14 | }
15 |
16 | .nav-search {
17 | background: rgba(242, 238, 230, 0.58) !important;
18 | }
19 |
20 | .search input {
21 | font-family: PingFangSC-Regular, HelveticaNeue-Light, 'Helvetica Neue Light', 'Microsoft YaHei', sans-serif;
22 | font-size: 14px;
23 | position: absolute;
24 | z-index: 1;
25 | top: 20px;
26 | right: 40px;
27 | width: 175px;
28 | height: 26px;
29 | transition: border .5s;
30 | border: none;
31 | outline: none;
32 | border-bottom: 1px solid #ccc;
33 | background: 0 0;
34 | -moz-transition: border .5s; /* Firefox 4 */
35 | -webkit-transition: border .5s; /* Safari and Chrome */
36 | -o-transition: border .5s;
37 |
38 | }
39 |
40 | .login > a {
41 | margin-top: 8px;
42 | }
43 |
44 | .btn-login {
45 | border: 1px solid #d8d8d8 !important;
46 | color: #b3acac;
47 | background-color: #5c6165;
48 | }
49 |
50 | .btn-login:hover, .btn-login:focus {
51 | color: #fff !important;
52 | background-color: #337ab7;
53 | border-color: #2e6da4;
54 | }
55 |
56 | .search input:focus {
57 | top: 15px;
58 | border-bottom: 3px solid #E67676;
59 | }
60 |
61 | .all-content {
62 | width: 65% !important;
63 | box-shadow: 0 0 15px 0 #CCC;
64 | background: #F6F4EC;
65 | margin: 0 auto 30px;
66 | border-radius: 3px;
67 | padding-bottom: 10px;
68 | min-height: 600px;
69 | margin-bottom: 70px;
70 | border: 1px solid #d8d8d8;
71 | background: url(../img/read_content.png) !important;
72 | }
73 |
74 | .title {
75 | position: relative;
76 | }
77 |
78 | .title > a.bookMark {
79 | position: absolute;
80 | background: url(../img/bookMark.png) no-repeat;
81 | width: 20px;
82 | height: 36px;
83 | right: 30px;
84 | top: -30px;
85 | cursor: pointer;
86 | }
87 |
88 | .title > a.bookMarkAct {
89 | position: absolute;
90 | background: url(../img/bookMark.png) no-repeat -20px 0;
91 | width: 22px;
92 | height: 39px;
93 | right: 30px;
94 | top: -30px;
95 | cursor: pointer;
96 | }
97 |
98 | .title > h2 {
99 | width: 100%;
100 | height: 40px;
101 | line-height: 40px;
102 | text-align: center;
103 | margin-top: 30px;
104 | margin-bottom: 30px;
105 | }
106 |
107 | .show-content, pre {
108 | width: 90%;
109 | line-height: 1.8;
110 | font-size: 16px !important;
111 | padding-top: 16px;
112 | min-height: 360px;
113 | margin-left: 5%;
114 | word-break: break-all;
115 | font-family: "Microsoft YaHei";
116 | text-align: left;
117 | position: relative;
118 | }
119 |
120 | pre {
121 | border: none !important;
122 | background: none !important;
123 | }
124 |
125 | .left-bar-list {
126 | width: 60px;
127 | position: fixed;
128 | left: 12%;
129 | }
130 |
131 | .left-bar-list .left-bar-flag {
132 | position: relative;
133 | z-index: 100;
134 | cursor: pointer;
135 | border: 1px solid rgba(0, 0, 0, .1);
136 | border-top: none;
137 | background: url("../img/left_bar_flag.png")
138 | }
139 |
140 | .left-bar-list .left-bar-flag .glyphicon {
141 | font-size: 18px;
142 | }
143 |
144 | .left-bar-list .left-bar-flag a {
145 | font: 12px/16px PingFangSC-Regular, '-apple-system', Simsun;
146 | display: block;
147 | width: 58px;
148 | height: 58px;
149 | transition: none;
150 | text-align: center;
151 | padding-top: 12px;
152 | color: #999;
153 | text-decoration: none;
154 | color: rgba(0, 0, 0, .4)
155 | }
156 |
157 | .left-bar-list .left-bar-flag a:hover, .add-color {
158 | color: #E67676 !important;
159 | }
160 |
161 | .show-content > p {
162 | font-size: 16px !important;
163 | }
164 |
165 | .show-content > #content {
166 | text-align: left !important;
167 | }
168 |
169 | .pre_next {
170 | width: 100%;
171 | height: 40px;
172 | text-align: center;
173 | margin-top: 20px;
174 | margin-bottom: 10px;
175 | }
176 |
177 | .pre_next > a:first-child {
178 | margin-right: 40%;
179 | }
180 |
181 | .pre_next > a {
182 | cursor: pointer;
183 | border: 1px solid rgba(90, 76, 76, 0.1);
184 | color: #555;
185 | background: rgba(0, 0, 0, .0001);
186 | }
187 |
188 | .pre_next > a:hover {
189 | border: 1px solid rgba(90, 76, 76, 0.1);
190 | color: #E67676;
191 | background: rgba(0, 0, 0, .0001);
192 | }
193 |
194 | .move {
195 | right: 5% !important;
196 | }
197 |
198 | /*原网页上一章下一章等隐藏*/
199 |
200 | .mingzhuPage, #htmlContent img, .chapter_Turnpage, #pageselect, .biao-qian-love-bd, #toplink, #tuijian, .chapter_Turnpage a, .bottem, .chapter h1, .content > center, .content p > strong, .content p > a {
201 | display: none !important;
202 | }
203 |
204 | @media (max-width: 1024px) {
205 | .left-bar-list, #cloud-tie-wrapper {
206 | display: none !important;
207 | }
208 |
209 | .all-content {
210 | width: 96% !important;
211 | }
212 |
213 | .move {
214 | display: none;
215 | }
216 |
217 | .search input {
218 | right: 0 !important;
219 | left: 0 !important;
220 | }
221 |
222 | .login > a {
223 | margin-top: 10px !important;
224 | }
225 |
226 | .title > h2 {
227 | font-size: 20px;
228 | }
229 | }
--------------------------------------------------------------------------------
/yournovel/static/js/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by howie on 17/02/2017.
3 | */
4 |
5 | $(function () {
6 | $('[data-toggle="popover"]').popover()
7 | });
8 |
9 |
10 | $(document).ready(function () {
11 | $('.move_up').click(function () {
12 | $('html, body').animate({scrollTop: 0}, 'slow');
13 | return false;
14 | });
15 | $('.move_down').click(function () {
16 | $('html, body, .content').animate({scrollTop: $(document).height()}, 300);
17 | return false;
18 | });
19 | // book
20 | $('#owllook_book').click(function () {
21 | var chapter_url = $("#chapter_url").val();
22 | var novels_name = $("#novels_name").val();
23 | if ($(this).hasClass('add-color')) {
24 | // delete book
25 | var del_pd = {"novels_name": novels_name, "chapter_url": chapter_url};
26 | $.ajax({
27 | type: "post",
28 | contentType: "application/json",
29 | url: "/operate/delete_book",
30 | data: del_pd,
31 | dataType: 'json',
32 | success: function (data) {
33 | if (data.status == 1) {
34 | $('#owllook_book').removeClass('add-color');
35 | }
36 | if (data.status == -1) {
37 | alert('您还没有登录');
38 | }
39 | }
40 | });
41 | } else {
42 | // add book
43 | last_read_url = window.location.pathname + window.location.search;
44 | var add_pd = {"novels_name": novels_name, "chapter_url": chapter_url, 'last_read_url': last_read_url};
45 | $.ajax({
46 | type: "post",
47 | contentType: "application/json",
48 | url: "/operate/add_book",
49 | data: add_pd,
50 | dataType: 'json',
51 | success: function (data) {
52 | if (data.status == 1) {
53 | $('#owllook_book').addClass('add-color');
54 | alert('已加入书架^_^');
55 | window.location.reload();
56 |
57 | }
58 | if (data.status == -1) {
59 | alert('您还没有登录');
60 | }
61 | }
62 | });
63 | }
64 | });
65 |
66 | // bookmark
67 | $('#bookMark').click(function () {
68 | var chapter_url = $("#chapter_url").val();
69 | var novels_name = $("#novels_name").val();
70 | var url = $("#url").val();
71 | var content_name = $("#content_name").text();
72 | bookmarkurl = "/owllook_content?url=" + url + "&name=" + content_name + "&chapter_url=" + chapter_url + "&novels_name=" + novels_name;
73 | if ($(this).hasClass('bookMark')) {
74 | // add bookmark
75 | var add_bm_pd = {'bookmark_url': bookmarkurl};
76 | $.ajax({
77 | type: "post",
78 | contentType: "application/json",
79 | url: "/operate/add_bookmark",
80 | data: add_bm_pd,
81 | dataType: 'json',
82 | success: function (data) {
83 | if (data.status == 1) {
84 | $('#bookMark').removeClass('bookMark');
85 | $('#bookMark').addClass('bookMarkAct');
86 | }
87 | if (data.status == -1) {
88 | alert('您还没有登录');
89 | }
90 | }
91 | });
92 | } else {
93 | // delete bookmark
94 | var del_bm_pd = {'bookmarkurl': bookmarkurl};
95 | $.ajax({
96 | type: "post",
97 | contentType: "application/json",
98 | url: "/operate/delete_bookmark",
99 | data: del_bm_pd,
100 | dataType: 'json',
101 | success: function (data) {
102 | if (data.status == 1) {
103 | $('#bookMark').removeClass('bookMarkAct');
104 | $('#bookMark').addClass('bookMark');
105 | }
106 | if (data.status == -1) {
107 | alert('您还没有登录');
108 | }
109 | }
110 | });
111 | }
112 | });
113 | // login
114 | $("#owllook_login").click(function () {
115 | var owllook_user = $("#owllook_user").val();
116 | var owllook_pass = $("#owllook_pass").val();
117 | if (owllook_user == "" || owllook_pass == "") {
118 | alert('不能有内容为空');
119 | } else {
120 | var login_pd = {'user': owllook_user, 'pwd': owllook_pass};
121 | $.ajax({
122 | type: "post",
123 | contentType: "application/json",
124 | url: "/operate/login",
125 | data: login_pd,
126 | dataType: 'json',
127 | success: function (data) {
128 | if (data.status == 1) {
129 | location.reload();
130 | }
131 | if (data.status == -1) {
132 | alert('用户名错误');
133 | }
134 | if (data.status == -2) {
135 | alert('密码错误');
136 | }
137 | }
138 | });
139 | }
140 | });
141 | // logout
142 | $("#logout").click(function () {
143 | $.ajax({
144 | type: "get",
145 | contentType: "application/json",
146 | url: "/operate/logout",
147 | dataType: 'json',
148 | success: function (data) {
149 | if (data.status == 1) {
150 | location.reload();
151 | }
152 | }
153 | });
154 | })
155 | });
156 |
157 | $('.we-button').popover({
158 | trigger: 'hover',
159 | html: true,
160 | content: "
关注后回复进群
"
161 | });
162 |
163 | $('.lcxs-button').popover({
164 | trigger: 'hover',
165 | html: true,
166 | content: "
微信关注粮草小说
"
167 | });
168 |
169 |
--------------------------------------------------------------------------------
/yournovel/static/css/web/chapter.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #E5E4DB !important
3 | }
4 |
5 | .all-chapter {
6 | margin-bottom: 50px;
7 | }
8 |
9 | #chapterlist .lm, .ablum_read, .TabCss .p10, .TabCss .h10, div.mb_21b, .booktext li center a, #ClassTitle, .bookurl, .booklist .vt, #bookname, #ad01, .shucansu, .samewriter, .bd > span, .bdsub > dl > dt, .all_ad, li.volume, #list > .notice, .cover, #new_chapter, .con_top, #sidebar, #fmimg, .tjlist, #listtj, #intro > p:last-child, #intro, .star_title, .starlist {
10 | display: none !important;
11 | }
12 |
13 | .mulu h1, .readout h1, #maininfo, .bdsub dd h1 {
14 | background: #F6F4EC;
15 | border-radius: 15px;
16 | margin-top: 35px;
17 | overflow: hidden;
18 | text-overflow: ellipsis;
19 | white-space: nowrap;
20 | padding-bottom: 25px;
21 | }
22 |
23 | .mulu h1, .readout h1 {
24 | text-align: center;
25 | line-height: 60px;
26 | height: 60px;
27 | }
28 |
29 | .bdsub dd h1 {
30 | text-align: center;
31 | padding-top: 20px;
32 | }
33 |
34 | #info h1 {
35 | text-align: center;
36 | padding-top: 20px;
37 | color: rgba(50, 68, 84, 0.61);
38 | }
39 |
40 | #info p {
41 | float: left;
42 | margin-top: 25px;
43 | width: 25%;
44 | margin-left: 6%;
45 | overflow: hidden;
46 | text-overflow: ellipsis;
47 | white-space: nowrap;
48 | }
49 |
50 | /* 区域1 */
51 | .chapters, .listmain, .story_list_m62topxs, .directory_con, .book-list, #yuedu table, .leftList, table.css, .dirconone, .book_list, #readerlist, .liebiao_bottom dl, .insert_list dl, .uclist, .list_box, .chapter, .mulu, #chapterslist, .booktext, #chapterslist dl, .box_chap, #book dl, .centent, #chapterlist, .booklist, #at, table.border, .zjlist, .mulu_list, .acss, .list, #xslist ul, .dirlist, .list-chapter, .list_box ul, #defaulthtml4 table, .article-list > dl, .update, #list .box, .bookcontent > dl, .listmain > dl, .ml_main > dl, #list dl, #chapter_list, .chapterlist, .mt10, .catalog, #readerlists, .readout table {
52 | overflow: hidden;
53 | padding-bottom: 1px;
54 | margin: auto;
55 | background: #F6F4EC;
56 | margin-top: 5px;
57 | border-radius: 15px;
58 | margin-bottom: 20px;
59 | }
60 |
61 | table.border, .mulu_list, #list, .article-list {
62 | margin-top: 35px;
63 | }
64 |
65 | /* 区域2 */
66 | .ml_list h3, .story-catalog h3.catalog-title, .listmain dl dt, .list .topfill h1, .story_list_m62topxs h2, .directory_con .tit, #yuedu table tr th, table.css td.vcss, .book_list h5, #main, .jm h3, #chapterlist .ui-title h3, #readerlist .topa, .insert_list dt, .uclist dt, .list_box td.list_line, .chapter .name, .mulu .mulu-title, #list dl dt h2, #chapterslist dt, .box_chap .t, .centent .list, .booklist .v, table.border .M, .zjlist dt, td.tcss, .acss .vcss, .list .tit, #xslist ul span, .article-list > dl > dt, .update .hd > #list .box-head, .bookcontent dt, .listmain dt, .bdsub tr th, #readerlists > ul > h3, #cl_content > dl > dt, #list dt, .panel > h2, .TabCss dt, .chapterlist > dt, .vcss, .readout td.vcss .chapter_list_chapter_title, .mt10 > .title > h2 {
67 | background: none repeat scroll 0 0 rgba(214, 212, 200, 0.89) !important;
68 | display: inline !important;
69 | float: left !important;
70 | font-size: 14px !important;
71 | line-height: 28px !important;
72 | overflow: hidden !important;
73 | text-align: center !important;
74 | vertical-align: middle !important;
75 | width: 100% !important;
76 | margin: auto auto 5px !important;
77 | padding: 5px 10px !important;
78 | }
79 |
80 | table.css {
81 | width: 100%;
82 | }
83 |
84 | /* 区域3 */
85 | .ml_list ul li, ul.chaw_c li, .mod-article-list li, .chapter, .story-catalog .catalog-list ul li, #chapter_list .chapter_list_chapterx, .listmain dl dd, .list .block_ul li, .story_list_m62topxs li, .directory_con .con li, .book-list li, #yuedu table tr li, .leftList li, table.css td.ccss, .dirconone ul li, .boxm ul li, .zjlist4 li, ul.pox li, .dccss, #readerlist ul li, .liebiao_bottom dd, .insert_list li, .uclist dd, .list_box td.list_lineb, .chapter li, #category .content .combox h2, .mulu li, .booktext li, #chapterslist dd, .book li, .art_listmain_main span, .box_chap li, #dirsort01 li, #book dd, .centent li, #chapterlist li, .booklist span, .box .zjlist4 li, .chapterlist li, #at td, .readout td, .zjlist dd, .mulu_list > li, .acss .ccss, .list .zl, #xslist ul li, .dirlist li, .list-chapter > li, .list_box ul li, #defaulthtml4 table .dccss, #defaulthtml4 table .dccss a, .article-list > dl > dd, .update .bd, #list td.swbt, .bookcontent dd, .listmain dd, .L, .ml_main > dl > dd, #readerlists > ul > li, .catalog > ul > li, .article_texttitleb > ul > li, #cl_content > dl > dd, #list dd, .panel li, .chapterlist > dd, td.ccss, .chapter_list_chapter, .book_list > ul > li {
86 | border-bottom: 1px dashed #CCC;
87 | display: inline;
88 | float: left;
89 | height: 25px;
90 | line-height: 200%;
91 | margin-bottom: 5px;
92 | text-align: left;
93 | text-indent: 10px;
94 | vertical-align: middle;
95 | width: 26%;
96 | font-size: 15px !important;
97 | margin-left: 5% !important;
98 | overflow: hidden;
99 | text-overflow: ellipsis;
100 | white-space: nowrap;
101 | }
102 |
103 | .TabCss dd.col4 {
104 | float: right;
105 | margin-right: 4px;
106 | }
107 |
108 | .TabCss dd {
109 | width: 228px !important;
110 | height: 28px;
111 | line-height: 28px;
112 | vertical-align: middle;
113 | text-indent: 10px;
114 | font-size: 12px;
115 | background: #E7F4F4;
116 | text-align: left;
117 | margin-left: 5px;
118 | margin-bottom: 5px;
119 | float: left;
120 | display: inline;
121 | border: 1px solid #9FBFE2;
122 | overflow: hidden;
123 | }
124 |
125 | dd > a {
126 | cursor: pointer;
127 | }
128 |
129 | .panel {
130 | margin-bottom: 20px;
131 | background-color: #E5E4DB !important;
132 | -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
133 | box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
134 | }
135 |
136 | tr > td.ccss, .L, ul#chapterlist li, .list_box td.list_lineb {
137 | width: 19% !important;
138 | }
139 |
140 | #at td.L {
141 | width: 14% !important;
142 | }
143 |
144 | .download-area, .list .part01, .list .part02, .list .topfill .right_juan, .pinglun, #main .kl, div#comment, #dirsort01 li strong, .notice, .zuixin10, .update h2, .bdsub dd h3, .bdsub .tags, .bdsub .tips {
145 | display: none !important;
146 | }
147 |
148 | .book_list > ul > li {
149 | width: 20% !important;
150 | float: right !important;
151 | }
152 |
153 | .boxm ul li {
154 | float: left !important;
155 | width: 25% !important;
156 | }
157 |
158 | #defaulthtml4 table .dccss {
159 | width: 100% !important;
160 | }
161 |
162 | @media (max-width: 960px) {
163 | li.chapter, .list_box td.list_lineb, .chapter li, #category .content .combox h2, .mulu li, .booktext li, #chapterslist dd, .book li, .art_listmain_main span, .box_chap li, #dirsort01 li, #book dd, .centent li, #chapterlist li, .booklist span, .box .zjlist4 li, .chapterlist li, #at td, .readout td, .zjlist dd, .mulu_list > li, .acss .ccss, .list .zl, #xslist ul li, .dirlist li, .list-chapter > li, .list_box ul li, #defaulthtml4 table .dccss, .article-list > dl > dd, .update .bd, #list td.swbt, .bookcontent dd, .listmain dd, .L, .ml_main > dl > dd, #readerlists > ul > li, .catalog > ul > li, .article_texttitleb > ul > li, #cl_content > dl > dd, #list dd, .panel li, .chapterlist > dd, td.ccss, .chapter_list_chapter, .book_list > ul > li {
164 | width: 100% !important;
165 | }
166 |
167 | }
168 |
169 |
170 |
--------------------------------------------------------------------------------
/yournovel/static/js/theme.js:
--------------------------------------------------------------------------------
1 | /*
2 | Created By MSCSTSTS
3 | 2017年10月11日 14:13:13 UTC+8
4 | */
5 |
6 |
7 | $(document).ready(function () {
8 | function theme(bg_color, bg_img, color , img){
9 | this.bg_color = bg_color;
10 | this.bg_img = bg_img;
11 | this.color = color;
12 | this.img = img;
13 | }
14 |
15 |
16 | /*-------------------初始化-------------------*/
17 | var base = [];
18 |
19 | base["http://qidian.gtimg.com/qd/images/read.qidian.com/body_base_bg.0.4.png"] = "../img/body_base_bg.0.4.png";
20 | base["http://qidian.gtimg.com/qd/images/read.qidian.com/basic_bg.0.4.png"] = "../img/basic_bg.0.4.png";
21 | base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/body_theme1_bg.0.4.png"] = "../img/body_theme1_bg.0.4.png";
22 | base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/theme_1_bg.0.4.png"] = "../img//theme_1_bg.0.4.png";
23 | base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/body_theme2_bg.0.4.png"] = "../img/body_theme2_bg.0.4.png";
24 | base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/theme_2_bg.0.4.png"] = "../img/theme_2_bg.0.4.png";
25 | base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/body_theme3_bg.0.4.png"] = "../img/body_theme3_bg.0.4.png";
26 | base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/theme_3_bg.0.4.png"] = "../img/theme_3_bg.0.4.png";
27 | base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/body_theme5_bg.0.4.png"] = "../img/body_theme5_bg.0.4.png";
28 | base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/theme_5_bg.0.4.png"] = "../img/theme_5_bg.0.4.png";
29 |
30 | var mise = new theme("rgb(237, 231, 218)", base["http://qidian.gtimg.com/qd/images/read.qidian.com/body_base_bg.0.4.png"],"rgba(0, 0, 0, 0)" ,base["http://qidian.gtimg.com/qd/images/read.qidian.com/basic_bg.0.4.png"] ); //米色
31 | var maihuang=new theme("rgb(224, 206, 158)" ,base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/body_theme1_bg.0.4.png"] ,"rgb(243, 233, 198)" ,base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/theme_1_bg.0.4.png"] ); //麦黄
32 | var yaqing = new theme("rgb(205, 223, 205)" , base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/body_theme2_bg.0.4.png"],"rgb(226, 238, 226)" ,base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/theme_2_bg.0.4.png"] );//雅青
33 | var hulan = new theme("rgb(207, 221, 225)" ,base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/body_theme3_bg.0.4.png"] ,"rgb(226, 239, 243)" ,base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/theme_3_bg.0.4.png"] );//湖蓝
34 | var danfen = new theme("rgb(235, 206, 206)","none" ,"rgb(245, 228, 228)" ,"none" );//淡粉
35 | var wuhui = new theme( "rgb(208, 208, 208)",base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/body_theme5_bg.0.4.png"] , "rgb(220, 220, 220)",base["http://qidian.gtimg.com/qd/images/read.qidian.com/theme/theme_5_bg.0.4.png"] );//雾灰
36 |
37 |
38 | var bg_target = $("body");
39 | var target = $("body > div.container.all-content");
40 | var setting = $("body > div.container.all-content > div.left-bar-list > div:nth-child(2)");
41 | var content = $($(".show-content").children("*").get(0));
42 | $("body").append('');
43 | $("body").append('');
44 | /*-------------------初始化-------------------*/
45 |
46 | var arr = [];
47 | arr["mise"]=mise;
48 | arr["maihuang"]=maihuang;
49 | arr["yaqing"]=yaqing;
50 | arr["hulan"]=hulan;
51 | arr["danfen"]=danfen;
52 | arr["wuhui"]=wuhui;
53 | var ff = [];
54 | ff['"Microsoft YaHei"']="yahei";
55 | ff["Microsoft YaHei"]="yahei";
56 | ff["Simsun"]="songti";
57 | ff['"Simsun"']="songti";
58 | ff["Kaiti"]="kaiti";
59 | ff['"Kaiti"']="kaiti";
60 | ff["yahei"]="Microsoft YaHei";
61 | ff["songti"]="Simsun";
62 | ff["kaiti"]="Kaiti";
63 | ff[""]="yahei";
64 |
65 | function Forcr_css(tar,att1,data1,data2){
66 | tar.css("cssText", att1+": url("+data2+") "+data1+"!important;");
67 | }
68 | function set_font(num){
69 | //console.log(num);
70 | //console.log("font-size:"+(fz-(-num))+"px !important;");
71 | content.css("cssText", "font-size: "+num+"px !important;");
72 | refresh_font_size();
73 | window.localStorage["theme-font-size"]=num;
74 | }
75 | function set_font_family(ff){
76 | content.removeClass("songti");
77 | content.removeClass("kaiti");
78 | content.removeClass("yahei");
79 | content.addClass(ff);
80 | //content.css("cssText", "font-family: "+ff+" !important;");
81 | refresh_font_family();
82 | window.localStorage["theme-font-family"]=ff;
83 | }
84 |
85 |
86 | function refresh_font_size(){
87 | $("#helper-font-size").text(content.css("font-size"));
88 | return parseInt(content.css("font-size"));
89 | }
90 | function refresh_font_family(){
91 | bright_font_family(content.attr("class"));
92 | //console.log(content.css("font-family"));
93 | return ff[content.css("font-family")];
94 | }
95 | function bright_font_family(ff){
96 | $("#helper div.family button").removeClass("act");
97 | $("#"+ff).addClass("act");
98 | }
99 | function change_Theme(theme){
100 | Forcr_css(bg_target,"background",theme.bg_color,theme.bg_img);
101 | var href =""+ window.location.href;
102 | if(href.indexOf("/chapter?")>0){
103 | Forcr_css($("#maininfo"),"background",theme.color,theme.img);
104 | Forcr_css($("#list > dl"),"background",theme.color,theme.img);
105 | Forcr_css($("div.container.all-chapter > div.inner > dl.chapterlist"),"background",theme.color,theme.img);
106 | Forcr_css($(" #at"),"background",theme.color,theme.img);
107 | Forcr_css($("div>dl"),"background",theme.color,theme.img);
108 | Forcr_css($("table"),"background",theme.color,theme.img);
109 | Forcr_css($("dl"),"background",theme.color,theme.img);
110 | Forcr_css($("ul"),"background",theme.color,theme.img);
111 | }
112 | else{
113 | Forcr_css(target,"background",theme.color,theme.img);
114 | }
115 | target.css("box-shadow","0 0 8px 1px rgba(100,100,100,0.4)");
116 | }
117 | $(document).ready(function(){
118 | if("undefined" == typeof localStorage["theme-color"]){
119 | }
120 | else{
121 | change_Theme(arr[localStorage["theme-color"]]);
122 | }
123 | if("undefined" == typeof localStorage["theme-font-size"]){
124 | }
125 | else{
126 | set_font(localStorage["theme-font-size"]);
127 | }
128 | if("undefined" == typeof localStorage["theme-font-family"]){
129 | }
130 | else{
131 | set_font_family(localStorage["theme-font-family"]);
132 | }
133 |
134 |
135 |
136 | setting.click(function(){
137 | event.preventDefault();
138 | /** Show Div**/
139 | $("#helper").toggle();
140 | $(".layer").toggle();
141 | refresh_font_size();
142 | refresh_font_family();
143 | });
144 | $("div.color").click(function(e){
145 | change_Theme(arr[$(this).attr("theme-data")]);
146 | window.localStorage["theme-color"] = $(this).attr("theme-data");
147 | });
148 | $("#helper-font-minus").click(function(){
149 | set_font((parseInt(refresh_font_size())-(1)));
150 | });
151 | $("#helper-font-plus").click(function(){
152 | set_font((parseInt(refresh_font_size())-(-1)));
153 | //console.log("+1");
154 | });
155 | $("#songti").click(function(){
156 | set_font_family("songti");
157 | });
158 | $("#yahei").click(function(){
159 | set_font_family("yahei");
160 | });
161 | $("#kaiti").click(function(){
162 | set_font_family("kaiti");
163 | });
164 | $(".layer").click(function(){
165 | $("#helper").hide();
166 | $(".layer").hide();
167 | });
168 | });
169 | });
--------------------------------------------------------------------------------
/yournovel/static/js/content.js:
--------------------------------------------------------------------------------
1 | /*
2 | Created By MSCSTSTS
3 | 2017-09-27 18:13:50 UTC+8
4 |
5 |
6 | Edit By MSCSTSTS
7 | 2017-12-02 19:36:17 UTC+8
8 | +触屏滑动切换上一章/下一章。
9 | +键盘左右方向键切换上一章/下一章。
10 |
11 | */
12 |
13 |
14 | //--------------------------------------------------------------------------------------------
15 |
16 | /*
17 | 登录、书签、加入书库等功能,都是基于刷新或者ajax
18 | 所以仅需修改部分页面
19 | 最后,将页面滑动到顶部即可。
20 | 处理逻辑:
21 | 1:页面加载,检查浏览器是否支持 ajax 和 sessionStorage
22 | 2:查询下一章 和 上一章是否已被缓存,若没有,则进行 ajax 请求,并将对应页面存入sessionStorage
23 | 3:点击上一章或下一章按钮以后,将缓存中的数据取出,重新渲染页面,回到顶部,修改浏览器url,并重新执行2
24 | 需要缓存的条目:
25 | 1:本页链接 data.url
26 | 2:下一章链接 data.next_chapter."下一章"
27 | 3:上一章链接 data.next_chapter."上一章"
28 | 4:章节名 data.name
29 | 5:小说名 data.novels_name
30 | 6:正文内容 data.soup
31 | 7:是否书签 data.bookmark
32 | 需要更新的页面内容:
33 | 0:【索引项】 页面链接(相对地址) 由 缓存数据的本页链接 拼接产生
34 | 1:书签状态 #bookMark 的 class ,根据 缓存数据 的 是否书签来定义 class
35 | 2:隐藏表单 page_url 的 value , 根据 缓存数据 的 本页链接
36 | 3:页面标题 page_title , 根据 缓存数据 的 章节名产生
37 | 4:正文文本 page_chapter_content ,根据 缓存数据 的 正文内容产生
38 | 5:上一章和下一章的地址 ,根据缓存数据的上一章链接和下一章链接产生
39 | 6:地址栏URL ,使用replaceState来更新,根据缓存数据的 本页链接 来拼接
40 | */
41 |
42 |
43 | $(document).ready(function () {
44 |
45 | var page_btn_pre = $("div.pre_next > a:nth-child(1)");
46 | var page_btn_next = $("div.pre_next > a:nth-child(2)");
47 | var page_title = $("title");
48 | var page_chapter_name = $("#content_name");
49 | // var page_chapter_content = $(".show-content>div");//正文
50 | var page_chapter_content = $($(".show-content").children("*").get(0)); //正文
51 | var page_bookmark = $("#bookMark");//书签,需要修改样式
52 | var page_url = $("#url");//页面隐藏表单,本页地址
53 |
54 | function get_chapter(n_url) {
55 | $.ajax({
56 | //提交数据的类型 POST GET
57 | type: "GET",
58 | //提交的网址
59 | url: n_url,
60 | //提交的数据
61 | data: {is_ajax: "owl_cache"},
62 | //返回数据的格式
63 | datatype: "json",//"xml", "html", "script", "json", "jsonp", "text".
64 | //在请求之前调用的函数
65 | //beforeSend:function(){$("#msg").html("logining");},
66 | //成功返回之后调用的函数
67 | success: function (data) {
68 | if (typeof data.name == "undefined") {
69 |
70 | } else { // 正确获取到数据
71 | var obj = {
72 | url: data.url,
73 | pre_chapter_url: transform(data.next_chapter)[0],
74 | next_chapter_url: transform(data.next_chapter)[1],
75 | name: data.name,
76 | novels_name: data.novels_name,
77 | content: data.soup,
78 | bookmark: data.bookmark,
79 | chapter_url: data.chapter_url
80 | };
81 | store(n_url, obj);
82 | }
83 | },
84 | //调用执行后调用的函数
85 | complete: function () {
86 |
87 | },
88 | //调用出错执行的函数
89 | error: function () {
90 | //请求出错处理
91 | }
92 | });
93 | }
94 |
95 | function transform(obj) {
96 | var arr = [];
97 | for (var item in obj) {
98 | arr.push(obj[item]);
99 | }
100 | return arr;
101 | }
102 |
103 | function store(n_url, obj) {
104 | window.sessionStorage.setItem(n_url, JSON.stringify(obj));
105 | }
106 |
107 | function ajax_content_init() {
108 | if (isSupport()) {
109 | log("支持sessionStorage,将为你开启页面缓存");
110 | search_url = window.location;
111 | // 来自书签页面的跳转不进行缓存
112 | if (search_url.search.indexOf("from_bookmarks") > 0) {
113 | log('来自书签页面的跳转不进行缓存')
114 | } else {
115 | ajax_task();
116 | page_bookmark.bind("click", function () {
117 | cache_reset();
118 | });
119 | }
120 | } else {
121 | //不支持
122 | return;
123 | }
124 | }
125 |
126 | function ajax_task() {
127 | store_query();//检查是否已缓存
128 | page_btn_pre.unbind("click");
129 | page_btn_pre.click(function () {
130 | event.preventDefault();
131 | if (window.sessionStorage.getItem(page_btn_pre.attr("href")) === null) {
132 | //若未缓存
133 | window.location.href = page_btn_pre.attr("href");
134 | } else {
135 | try {
136 | load(page_btn_pre.attr("href"));
137 | } catch (err) {
138 | window.location.href = page_btn_pre.attr("href");
139 | }
140 |
141 | }
142 | });
143 | page_btn_next.unbind("click");
144 | page_btn_next.click(function () {
145 | event.preventDefault();
146 | if (window.sessionStorage.getItem(page_btn_next.attr("href")) === null) {
147 | //若未缓存
148 | window.location.href = page_btn_next.attr("href");
149 | } else {
150 | try {
151 | load(page_btn_next.attr("href"));
152 | } catch (err) {
153 | window.location.href = page_btn_next.attr("href");
154 | }
155 |
156 | }
157 | });
158 | }
159 |
160 |
161 | function load_bookmark(data) {
162 | page_bookmark.removeClass("bookMark");
163 | page_bookmark.removeClass("bookMarkAct");
164 | //log(data.bookmark);
165 | if (data.bookmark == 0) {
166 | page_bookmark.addClass("bookMark");
167 | } else {
168 | page_bookmark.addClass("bookMarkAct");
169 | }
170 | }
171 |
172 | function load_hiddenForm(data) {
173 | page_url.val(data.url);
174 | }
175 |
176 | function load_title(data) {
177 | page_title.html(data.name + " - owllook");
178 | }
179 |
180 | function stripscript(s) {//用于过滤script标签
181 | return s.replace(/