From 4196be4f670055322a10244138a204ffb9870743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AB=8F=E8=A8=AA=E5=AD=90?= Date: Wed, 21 Jan 2026 03:36:13 +0900 Subject: [PATCH] =?UTF-8?q?SVN=E3=81=8B=E3=82=89=E3=81=AE=E3=83=9F?= =?UTF-8?q?=E3=83=A9=E3=83=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 39 +++++++ LICENSE.txt | 13 +++ Makefile | 69 ++++++++++++ README.md | 85 +++++++++++++++ check.go | 64 +++++++++++ config.go | 66 +++++++++++ config.json | 6 + go.mod | 8 ++ go.sum | 4 + lib.go | 44 ++++++++ logo.jpg | Bin 0 -> 13273 bytes main.go | 52 +++++++++ page.go | 115 ++++++++++++++++++++ rmbloat.go | 203 ++++++++++++++++++++++++++++++++++ spliti.1 | 28 +++++ srv.go | 89 +++++++++++++++ static/favicon.ico | Bin 0 -> 15406 bytes static/git.png | Bin 0 -> 8536 bytes static/logo.jpg | Bin 0 -> 13273 bytes static/style.css | 266 +++++++++++++++++++++++++++++++++++++++++++++ view/404.html | 4 + view/footer.html | 9 ++ view/header.html | 16 +++ view/index.html | 21 ++++ view/news.html | 3 + 25 files changed, 1204 insertions(+) create mode 100644 CHANGELOG.md create mode 100644 LICENSE.txt create mode 100644 Makefile create mode 100644 README.md create mode 100644 check.go create mode 100644 config.go create mode 100644 config.json create mode 100644 go.mod create mode 100644 go.sum create mode 100644 lib.go create mode 100644 logo.jpg create mode 100644 main.go create mode 100644 page.go create mode 100644 rmbloat.go create mode 100644 spliti.1 create mode 100644 srv.go create mode 100644 static/favicon.ico create mode 100644 static/git.png create mode 100644 static/logo.jpg create mode 100644 static/style.css create mode 100644 view/404.html create mode 100644 view/footer.html create mode 100644 view/header.html create mode 100644 view/index.html create mode 100644 view/news.html diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c76dd4c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,39 @@ +# 2.3.0 +* GPL → ISC + +# 2.2.0 +* GNU MakeからBSD Makeに変更 +* 社会、トレンド、地域、海外、コラム、及びライフスタイルのカテゴリページの修正 +* マウスオーバーのハイライトの追加 +* .pageList02のスタイリングの追加 + +# 2.1.0 +* 出版社ページを追加 +* 出版社ページのページネーション +* カテゴリーのページネーション +* つぶやきを見るページ(list_quote.pl)を追加 + +# 2.0.1 +* manページを修正 +* 「-h」を修正 +* エラーページを修正 + +# 2.0.0 +* PHPからGo言語に交換しました + +# 1.1.2 +* 投稿内の画像もプロクシー化 +* 投稿内の画像はレスポンシブに + +# 1.1.1 +* YouTube動画があれば、オワコンYouTubeに変更させる様に +* サムネイルがなければ、getimg()関数をす部に終了する様に +* もっと小さいバグを修正 + +# 1.1.0 +* 画像はimgproxy化 +* カテゴリーを追加 +* ホームページを追加(普通Mixiにアクセスするのは不要になった) + +# 1.0.0 +* 最初リリース diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..777a97f --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,13 @@ +Copyright © 2018-2024 by 076.moe + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD +TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..86218b5 --- /dev/null +++ b/Makefile @@ -0,0 +1,69 @@ +NAME!=cat main.go | grep "var sofname" | awk '{print $$4}' | sed "s/\"//g" +VERSION!=cat main.go | grep "var version" | awk '{print $$4}' | sed "s/\"//g" +# Linux、Haiku、Illumos = /usr、FreeBSDとOpenBSD = /usr/local、NetBSD = /usr/pkg +PREFIX=/usr/local +MANPREFIX=${PREFIX}/share/man +# FreeBSD = /usr/local/etc、NetBSD = /usr/pkg/etc、それ以外 = /etc +CNFPREFIX?=/etc +CC=CGO_ENABLED=0 go build +# リリース。なし=デバッグ。 +RELEASE=-ldflags="-s -w" -buildvcs=false + +all: + ${CC} ${RELEASE} -o ${NAME} + +release: + env GOOS=linux GOARCH=amd64 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-linux-amd64 + env GOOS=linux GOARCH=arm64 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-linux-arm64 + env GOOS=linux GOARCH=arm ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-linux-arm + env GOOS=linux GOARCH=riscv64 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-linux-riscv64 + env GOOS=linux GOARCH=386 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-linux-386 + env GOOS=linux GOARCH=ppc64 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-linux-ppc64 + env GOOS=linux GOARCH=mips64 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-linux-mips64 + env GOOS=openbsd GOARCH=amd64 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-openbsd-amd64 + env GOOS=openbsd GOARCH=386 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-openbsd-386 + env GOOS=openbsd GOARCH=arm64 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-openbsd-arm64 + env GOOS=openbsd GOARCH=arm ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-openbsd-arm + env GOOS=openbsd GOARCH=mips64 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-openbsd-mips64 + env GOOS=freebsd GOARCH=amd64 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-freebsd-amd64 + env GOOS=freebsd GOARCH=386 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-freebsd-386 + env GOOS=freebsd GOARCH=arm ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-freebsd-arm4 + env GOOS=freebsd GOARCH=arm64 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-freebsd-arm64 + env GOOS=freebsd GOARCH=riscv64 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-freebsd-riscv64 + env GOOS=netbsd GOARCH=amd64 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-netbsd-amd64 + env GOOS=netbsd GOARCH=386 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-netbsd-386 + env GOOS=netbsd GOARCH=arm ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-netbsd-arm4 + env GOOS=netbsd GOARCH=arm64 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-netbsd-arm64 + env GOOS=illumos GOARCH=amd64 ${CC} ${RELEASE} -o bin/${NAME}-${VERSION}-illumos-amd64 + +clean: + rm -f ${NAME} ${NAME}-${VERSION}.tar.gz + +dist: clean + mkdir -p ${NAME}-${VERSION} + cp -R LICENSE.txt Makefile README.md CHANGELOG.md\ + view static logo.jpg\ + ${NAME}.1 *.go *.json go.mod go.sum ${NAME}-${VERSION} + tar zcfv ${NAME}-${VERSION}.tar.gz ${NAME}-${VERSION} + rm -rf ${NAME}-${VERSION} + +config: + mkdir -p ${DESTDIR}${CNFPREFIX}/spliti + cp config.json ${DESTDIR}${CNFPREFIX}/spliti + +install: all + mkdir -p ${DESTDIR}${PREFIX}/bin + cp -f ${NAME} ${DESTDIR}${PREFIX}/bin + chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME} + mkdir -p ${DESTDIR}${MANPREFIX}/man1 + sed "s/VERSION/${VERSION}/g" < ${NAME}.1 > ${DESTDIR}${MANPREFIX}/man1/${NAME}.1 + chmod 644 ${DESTDIR}${MANPREFIX}/man1/${NAME}.1 + mkdir -p ${DESTDIR}${CNFPREFIX}/${NAME} + chmod 755 ${DESTDIR}${CNFPREFIX}/${NAME} + +uninstall: + rm -f ${DESTDIOR}${PREFIX}/bin/${NAME}\ + ${DESTDIR}${MANPREFIX}/man1/${NAME}.1\ + ${DESTDIR}${CNFPREFIX}/${NAME} + +.PHONY: all release clean dist config install uninstall diff --git a/README.md b/README.md new file mode 100644 index 0000000..5967c50 --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +# spliti + +mixi向けプライバシーUI。 + +## 設置方法 + +### すべてのOS + +```sh +$domain="example.com" +cd /var/www/htdocs +git clone https://gitler.moe/suwako/spliti.git && cd spliti +find . -type f -name "config.json" -exec sed -i 's/mixi.076.moe/$domain/g' +``` + +### OpenBSD(オススメ) + +```sh +make +doas make install +doas make config +cd /etc +wget https://076.moe/repo/webserver/relayd/spliti.conf +mv spliti.conf relayd.conf +find . -type f -name "/etc/relayd.conf" -exec sed -i 's/DOMAIN/$domain/g' +rcctl restart relayd +``` + +### Linux + +**注意:BSD Makeをインストールして下さい。GNU Makeは未対応です。** + +```sh +bmake +doas bmake install PREFIX=/usr +doas bmake config +cp /etc/nginx/sites-enabled +wget https://076.moe/repo/webserver/nginx/spliti.conf +find . -type f -name "/etc/nginx/sites-enabled/spliti.conf" -exec sed -i 's/DOMAIN/$domain/g' +/etc/init.d/nginx restart +``` + +### FreeBSD + +```sh +make +doas make install +doas make config CNFPREFIX=/usr/local/etc +cp srv/nginx.conf /usr/local/etc/nginx/sites-enabled/spliti.conf +wget https://076.moe/repo/webserver/nginx/spliti.conf +find . -type f -name "/usr/local/etc/nginx/sites-enabled/spliti.conf" -exec sed -i 's/DOMAIN/$domain/g' +service nginx restart +``` + +### NetBSD + +```sh +make +doas make install +doas make config CNFPREFIX=/usr/pkg/etc +cp srv/nginx.conf /usr/pkg/etc/nginx/sites-enabled/spliti.conf +wget https://076.moe/repo/webserver/nginx/spliti.conf +find . -type f -name "/usr/pkg/etc/nginx/sites-enabled/spliti.conf" -exec sed -i 's/DOMAIN/$domain/g' +service nginx restart +``` + +## インスタンス一覧 + +### 一般ネット + +| ウエブサイト | [クラフレ](http://jezf25zgvxlsvuzdzm6fg2hoetmruhy4uxnolyw46tuh4jugcwc7byqd.onion/Cloudflare%E3%82%92%E4%BD%BF%E3%82%8F%E3%81%AA%E3%81%84%E7%90%86%E7%94%B1%EF%BC%88%E3%83%AA%E3%83%81%E3%83%A3%E3%83%BC%E3%83%89%E3%83%BB%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%83%9E%E3%83%B3%EF%BC%89) | 注 | +| -- | -- | -- | +| [https://mixi.076.moe/](https://mixi.076.moe/) | 無 | 公式インスタンス | + +### Tor + +| オニオン | 注 | +| -- | -- | +| | | + +### I2P + +| イープサイト | 注 | +| -- | -- | +| | | diff --git a/check.go b/check.go new file mode 100644 index 0000000..0bb997f --- /dev/null +++ b/check.go @@ -0,0 +1,64 @@ +package main + +import ( + "strings" + "net/url" + "fmt" +) + +func getid(u string) (string, error) { + parse, err := url.Parse(u) + if err != nil { + return "", err + } + + params, err := url.ParseQuery(parse.RawQuery) + if err != nil { + return "", err + } + + id, ok := params["id"] + if !ok || len(id) == 0 { + return "", fmt.Errorf("IDを見つけられませんでした。") + } + + return id[0], nil +} + +/* 記事かの確認 */ +func isarticle(u string) bool { + chk := strings.Split(u, "=") + return len(chk) > 2 && + (chk[0] == "/view_news.pl?id" || chk[0] == "/view_news.pl?from" || chk[0] == "/view_news.pl?media_id" || chk[0] == "/view_news.pl?stkt") +} + +/* 部分圏かの確認 */ +func issubcat(u string) bool { + chk := strings.Split(u, "=") + return len(chk) > 1 && + (chk[0] == "/list_news_category.pl?id" || chk[0] == "/list_news_category.pl?page" || chk[0] == "/list_news_category.pl?sort" || chk[0] == "/list_news_category.pl?type" || chk[0] == "/list_news_category.pl?sub_category_id") && + strings.Contains(u, "type=bn") +} + +/* 部分かの確認 */ +func iscategory(u string) bool { + chk := strings.Split(u, "=") + return len(chk) > 1 && + (chk[0] == "/list_news_category.pl?id" || chk[0] == "/list_news_category.pl?sub_category_id" || chk[0] == "/list_news_category?from") && + !strings.Contains(u, "type=bn") +} + +/* 出版社かの確認 */ +func ispublish(u string) bool { + chk := strings.Split(u, "=") + return len(chk) > 1 && (chk[0] == "/list_news_media.pl?id" || chk[0] == "/list_news_media.pl?page") +} + +/* つぶやきかの確認 */ +func istubayaki(u string) bool { + chk := strings.Split(u, "=") + return len(chk) > 1 && + (chk[0] == "/list_quote.pl?id" || chk[0] == "/list_quote.pl?type" || chk[0] == "/list_quote.pl?sort" || chk[0] == "/list_quote.pl?news_id") && + strings.Contains(u, "type=voice") && + (strings.Contains(u, "sort=post_time") || strings.Contains(u, "sort=feedback_count")) +} diff --git a/config.go b/config.go new file mode 100644 index 0000000..e49a173 --- /dev/null +++ b/config.go @@ -0,0 +1,66 @@ +package main + +import ( + "fmt" + "encoding/json" + "io/ioutil" + "runtime" + "os" + "errors" + "strings" +) + +type Config struct { + configpath, webpath, domain, imgproxy, ip string +} + +func getconf () (Config, error) { + var cnf Config + + prefix := "/usr" + if runtime.GOOS == "freebsd" || runtime.GOOS == "openbsd" { + prefix += "/local" + } else if runtime.GOOS == "netbsd" { + prefix += "/pkg" + } + + cnf.configpath = "/etc/spliti/config.json" + if runtime.GOOS == "freebsd" || runtime.GOOS == "netbsd" { + cnf.configpath = prefix + cnf.configpath + } + + data, err := ioutil.ReadFile(cnf.configpath) + if err != nil { + fmt.Println("config.jsonを開けられません: ", err) + return cnf, errors.New("コンフィグファイルは " + cnf.configpath + " に創作して下さい。") + } + + var payload map[string]interface{} + json.Unmarshal(data, &payload) + if payload["webpath"] == nil { + payload["webpath"] = "/var/www/htdocs/spliti" + } + if payload["domain"] == nil { + return cnf, errors.New("「domain」の値が設置していません。") + } + if payload["imgproxy"] == nil { + payload["imgproxy"] = "https://imgproxy.076.moe" + } + if payload["ip"] == nil { + payload["ip"] = "0.0.0.0" + } + if _, err := os.Stat(payload["webpath"].(string)); err != nil { + fmt.Printf("%v\n", err) + return cnf, errors.New("mkdirコマンドを使って、 " + payload["webpath"].(string)) + } + if !strings.HasPrefix(payload["domain"].(string), "http://") && !strings.HasPrefix(payload["domain"].(string), "https://") { + return cnf, errors.New("URLは「http://」又は「https://」で始める様にして下さい。") + } + cnf.webpath = payload["webpath"].(string) + cnf.domain = payload["domain"].(string) + cnf.imgproxy = payload["imgproxy"].(string) + cnf.ip = payload["ip"].(string) + payload = nil + + return cnf, nil +} diff --git a/config.json b/config.json new file mode 100644 index 0000000..35ef0c0 --- /dev/null +++ b/config.json @@ -0,0 +1,6 @@ +{ + "domain": "https://mixi.076.moe", + "webpath": "/var/www/htdocs/spliti", + "imgproxy": "https://imgproxy.076.moe", + "ip": "0.0.0.0" +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..440c2d4 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module spliti + +go 1.20 + +require ( + golang.org/x/net v0.17.0 + golang.org/x/text v0.14.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..cf89ff9 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= diff --git a/lib.go b/lib.go new file mode 100644 index 0000000..ff98ee4 --- /dev/null +++ b/lib.go @@ -0,0 +1,44 @@ +package main + +import ( + "io" + "strings" + "bytes" + + "golang.org/x/net/html" + "golang.org/x/text/encoding/japanese" + "golang.org/x/text/transform" +) + +/* PHPであるstrip_tagsはGo言語で存在しないから、自分で作る */ +func strip_tags(data string) string { + doc, err := html.Parse(strings.NewReader(data)) + if err != nil { + panic("HTMLをパーシングに失敗。") + } + + var buf bytes.Buffer + var f func(*html.Node) + f = func(n *html.Node) { + if n.Type == html.TextNode { + buf.WriteString(n.Data) + } + for c := n.FirstChild; c != nil; c = c.NextSibling { + f(c) + } + } + f(doc) + + return buf.String() +} + +func EUCJPToUTF8(input []byte) (string, error) { + transformer := japanese.EUCJP.NewDecoder() + reader := transform.NewReader(bytes.NewReader(input), transformer) + result, err := io.ReadAll(reader) + if err != nil { + return "エンコーディングに失敗", err + } + + return string(result), nil +} diff --git a/logo.jpg b/logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1a7486ab2486962613c3e509d107712fff2909eb GIT binary patch literal 13273 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 _lJ|K8l?5~*aICi>Ph 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 PmUG$Pfa5pdZR!63%aoNJ literal 0 HcmV?d00001 diff --git a/main.go b/main.go new file mode 100644 index 0000000..492e98a --- /dev/null +++ b/main.go @@ -0,0 +1,52 @@ +package main + +import ( + "fmt" + "os" + "strconv" +) + +var sofname = "spliti" +var version = "2.3.0" + +func help() { + fmt.Println("076 " + sofname + "-" + version + " - mixi向けプライバシーUI") + fmt.Println("https://mixi.076.moe/ | https://gitler.moe/suwako/spliti") + fmt.Println("") + fmt.Println("使い方:") + fmt.Println(sofname + " -v :バージョンを表示") + fmt.Println(sofname + " -s [ポート番号] :ポート番号でウエブサーバーを実行(デフォルト=9930)") + fmt.Println(sofname + " -h :ヘルプを表示") +} + +func main() { + cnf, err := getconf() + if err != nil { + fmt.Println(err) + return + } + + args := os.Args + + if len(args) == 3 && args[1] == "-s" { + if port, err := strconv.Atoi(args[2]); err != nil { + fmt.Printf("%qは数字ではありません。\n", args[2]) + return + } else { + serv(cnf, port) + return + } + } else if len(args) == 2 { + if args[1] == "-v" { + fmt.Println(sofname + "-" + version) + } else if args[1] == "-s" { + serv(cnf, 9930) + } else { + help() + return + } + } else { + help() + return + } +} diff --git a/page.go b/page.go new file mode 100644 index 0000000..11cb6a9 --- /dev/null +++ b/page.go @@ -0,0 +1,115 @@ +package main + +import ( + "fmt" + "io" + "net/http" + "regexp" + "strings" +) + +/* ページのタイトル */ +func gettitle(str string) string { + re := regexp.MustCompile("(.*)") + matches := re.FindStringSubmatch(str) + if len(matches) > 1 { + return matches[1] + } + return "" +} + +func getimg(str string, cnf Config) string { + re := regexp.MustCompile(``) + matches := re.FindStringSubmatch(str) + if len(matches) > 1 { + return strings.Replace(matches[1], "https://", cnf.imgproxy+"/", -1) + } + return "" +} + +func getdesc(str string) string { + re := regexp.MustCompile(`
(.*?)
`) + res := re.ReplaceAllString(str, "") + return strip_tags(res) +} + +/* 記事の受取 */ +func get(url string, cnf Config) map[string]string { + // デフォルト=エラー + res := make(map[string]string) + res["title"] = "見つけられない" + res["content"] = ` +
+
+

見つけられなかった

+
+
+
+
+

ごめんね!

+
+
+ ` + res["img"] = "" + res["desc"] = "" + res["err"] = "" + + resp, err := http.Get("https://news.mixi.jp" + url) + if err != nil { + res["err"] = "URLエラー" + fmt.Println(res["err"] + ": " + err.Error()) + return res + } + defer resp.Body.Close() + + if resp.StatusCode == http.StatusOK { + bytebody, err := io.ReadAll(resp.Body) + if err != nil { + res["err"] = "内容はバイトコードとして読み込みに失敗。" + fmt.Println(res["err"]) + return res + } + + body, err := EUCJPToUTF8(bytebody) + if err != nil { + res["err"] = err.Error() + fmt.Println(res["err"]) + return res + } + + id, _ := getid(url) + + res["title"] = gettitle(body) + if isarticle(url) { + if !strings.Contains(body, "newsArticle") { + res["content"] = rmebloat(body, cnf) + } else { + res["img"] = getimg(body, cnf) + res["content"] = rmbloat(id, body, cnf) + } + } else if ispublish(url) { + res["content"] = rmpbloat(body, cnf) + } else if issubcat(url) { + if strings.Contains(body, `

存在しないカテゴリです

`) { + res["content"] = rmebloat(body, cnf) + } else { + res["content"] = rmsbloat(body, cnf) + } + } else if istubayaki(url) { + if !strings.Contains(body, "quoteList") { + res["content"] = rmebloat(body, cnf) + } else { + res["content"] = rmqbloat(body, cnf) + } + } else { + if !strings.Contains(body, "注目のニュース") { + res["content"] = rmebloat(body, cnf) + } else { + res["content"] = rmcbloat(body, cnf) + } + } + res["desc"] = getdesc(res["content"]) + } + + return res +} diff --git a/rmbloat.go b/rmbloat.go new file mode 100644 index 0000000..fbab1e3 --- /dev/null +++ b/rmbloat.go @@ -0,0 +1,203 @@ +package main + +import ( + "regexp" + "strings" +) + +/* カテゴリーだけが残るまで消す */ +func rmcbloat(body string, cnf Config) string { + var re *regexp.Regexp + + rep := []struct { + pat string + repl string + }{ + {`(?s).*?`, ""}, + {`(?s).*?`, ""}, + {`(?s)
.*?
`, ""}, + {`(?s)