commit 8bc2fa7dfdd716aeaa51163cfaa635f4ade2b29b Author: 諏訪子 Date: Wed Jan 21 03:59:11 2026 +0900 SVNからのミラー diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..3aa3788 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,22 @@ +# 1.3.0 +* BSD2clause→ISCライセンスに変更 +* 変なエンコーディングの変換 + +# 1.2.0 +* 静的ファイルの修正 +* 新しいルールに従い +* GNU MakeからBSD Makeに変更 +* GPLv2→BSD2clouseライセンスに変更 + +# 1.1.0 +* 言語はliblocale化 +* 複数言語対応 +* NetBSD対応 +* IPアドレスを設定する様に + +# 1.0.0 +* PHPからGoに交換しました +* 今度からバージョンを付きます + +# それ以前 +* 色々 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..92a29db --- /dev/null +++ b/Makefile @@ -0,0 +1,65 @@ +NAME!=cat common/common.go | grep "var sofname" | awk '{print $$4}' | sed "s/\"//g" +VERSION!=cat common/common.go | grep "var version" | awk '{print $$4}' | sed "s/\"//g" +PREFIX=/usr/local +MANPREFIX=${PREFIX}/man +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 common src logo.jpg\ + ${NAME}.1 main.go *.json go.mod go.sum ${NAME}-${VERSION} + tar zcfv ${NAME}-${VERSION}.tar.gz ${NAME}-${VERSION} + rm -rf ${NAME}-${VERSION} + +install: + 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}${PREFIX}/share/${NAME}/archive + chmod 755 ${DESTDIR}${PREFIX}/share/${NAME}/archive + 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}\ + ${DESTDIR}${PREFIX}/share/${NAME} + +.PHONY: all release clean dist install uninstall diff --git a/README.md b/README.md new file mode 100644 index 0000000..bf6b8b0 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# 保存サイト +世界初FOSS系ウエブアーカイバーです。 + +# インストールする方法 +## OpenBSD +```sh +cd hozonsite +make +doas make install +``` + +## FreeBSD +```sh +cd hozonsite +make +doas make install MANPREFIX=/usr/local/share/man +``` + +## NetBSD +```sh +cd hozonsite +make +doas make install PREFIX=/usr/pkg MANPREFIX=/usr/pkg/share/man +``` + +## Linux +```sh +cd hozonsite +bmake +doas bmake install PREFIX=/usr MANPREFIX=/usr/share/man +``` diff --git a/common/common.go b/common/common.go new file mode 100644 index 0000000..daebf8b --- /dev/null +++ b/common/common.go @@ -0,0 +1,12 @@ +package common + +var sofname = "hozonsite" +var version = "1.3.0" + +func GetSofname() string { + return sofname +} + +func GetVersion() string { + return version +} diff --git a/config.json b/config.json new file mode 100644 index 0000000..3e269bf --- /dev/null +++ b/config.json @@ -0,0 +1,5 @@ +{ + "webpath": "/var/www/htdocs/hozonsite", + "domain": "https://hozon.site", + "ip": "0.0.0.0" +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..6e49e28 --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module gitler.moe/suwako/hozonsite + +go 1.20 + +require gitler.moe/suwako/goliblocale v1.0.0 + +require golang.org/x/text v0.14.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..f49f910 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +gitler.moe/suwako/goliblocale v1.0.0 h1:QiQKNzdgpavwmAaYhAb5pth0I6qS8IJ7q2hYAgpXacU= +gitler.moe/suwako/goliblocale v1.0.0/go.mod h1:pdv9Go5taevY8ClBOA+oLXjGap7G1RmIVKUMF8HSJmU= +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/hozonsite.1 b/hozonsite.1 new file mode 100644 index 0000000..86f6ea3 --- /dev/null +++ b/hozonsite.1 @@ -0,0 +1,33 @@ +.TH 保存サイト 1 hozonsite\-VERSION +.SH ソフト名 +保存サイト - 世界初FOSS系ウエブアーカイバー +.SH 概要 +.B hozonsite +[\fI\,オプション\/\fR] [\fI\,ポート番号\/\fR] +.SH 説明 +.PP +保存サイトは世界初FOSS系ウエブアーカイバーです。 +.TP +\fB\-v\fR +バージョンを表示 +.TP +\fB\-s [ポート番号]\fR +ポート番号でサーバーを開始(デフォルト=9920) +.TP +\fB\-h\fR +ヘルプを表示 +.TP +.B オプションなし +ローカルにウェブページを保存 +.SH 会話 +.PP +XMPP: xmpp:hozonsite@chat.xmpp.076.ne.jp?join +.br +IRC: irc.076.ne.jp/6697 #hozonsite +.br +メーリングリスト: (開発中) +.SH バグ報告 +.PP +バグは下記のURLまでご報告下さい: +.br +https://gitler.moe/suwako/hozonsite/issues diff --git a/locale/en.json b/locale/en.json new file mode 100644 index 0000000..0aa2d36 --- /dev/null +++ b/locale/en.json @@ -0,0 +1,17 @@ +{ + "hozonsite": "Hozon Site", + "desc": "It is the world's first FOSS web archiver.", + "logo": "Logo", + "top": "Top", + "langchange": "Language change", + "totop": "Return to toppage", + "tophe": "To toppage.", + "topwhatsave": "Which page will you archive?", + "hozon": "Archive", + "archwhozonsite": "Archived with Hozon Site.", + "areadyhozon": "Pages that already got archived:", + "willreallyhozon": "This page seems to have been already archived.
Do you really want to proceed?", + "yesreallyhozon": "Yes, please archive!!", + "errfuseiurl": "The URL should start with \"http://\" or \"https://\".", + "errfusei": "Unknown error." +} diff --git a/locale/ja.json b/locale/ja.json new file mode 100644 index 0000000..a27b2c1 --- /dev/null +++ b/locale/ja.json @@ -0,0 +1,17 @@ +{ + "hozonsite": "保存サイト", + "desc": "世界初FOSS系ウエブアーカイバーです。", + "logo": "ロゴ", + "top": "トップ", + "langchange": "言語変更", + "totop": "トップページに戻る", + "tophe": "トップページへ", + "topwhatsave": "どのページを保存しますか?", + "hozon": "保存", + "archwhozonsite": "保存サイトでアーカイブしました。", + "areadyhozon": "既に保存されたページ:", + "willreallyhozon": "このページが既に保存されているみたいです。
本当に手続きましょうか?", + "yesreallyhozon": "はい、保存して下さい!!", + "errfuseiurl": "URLは「http://」又は「https://」で始めます。", + "errfusei": "不正なエラー。" +} diff --git a/logo.jpg b/logo.jpg new file mode 100644 index 0000000..38cb353 Binary files /dev/null and b/logo.jpg differ diff --git a/main.go b/main.go new file mode 100644 index 0000000..9ef2235 --- /dev/null +++ b/main.go @@ -0,0 +1,113 @@ +package main + +import ( + "fmt" + "os" + "strings" + "strconv" + + "gitler.moe/suwako/hozonsite/src" + "gitler.moe/suwako/hozonsite/common" +) + +func help() { + fmt.Println("使い方:") + fmt.Println( + common.GetSofname() + " -v :バージョンを表示", + ) + fmt.Println( + common.GetSofname() + + " -s [ポート番号] :ポート番号でウェブサーバーを実行(デフォルト=9920)", + ) + fmt.Println( + common.GetSofname() + + " -h :ヘルプを表示", + ) + fmt.Println( + common.GetSofname() + + " :コマンドラインでウェブサイトを保存", + ) +} + +func saveurlcmd(url string, cnf src.Config) { + // 結局HTTPかHTTPSじゃないわね… + if !src.Checkprefix(url) { + fmt.Println("URLは不正です。終了…") + return + } + + // パラメートルの文字(?、=等)を削除 + eurl := src.Stripurl(url) + + // 既に/usr/local/share/hozonsite/archiveに存在するかどうか + exist := src.Checkexist(eurl, cnf.Datapath) + + // 既に存在したら、使う + var confirm string + + // あ、既に存在する + if len(exist) > 0 { + fmt.Println("このページが既に保存されているみたいです。") + fmt.Println("本当に手続きましょうか? [y/N]") + + // 既に存在するページのURLを表示 + for _, ex := range exist { + fmt.Println(strings.Replace(ex, cnf.Datapath, cnf.Domain, 1)) + } + fmt.Scanf("%s", &confirm) + } + + // 存在しない OR 「本当に手続きましょうか?」でYを入力した場合 + if len(exist) == 0 || confirm == "y" || confirm == "Y" { + path := src.Mkdirs(eurl, cnf.Datapath) + // ページをダウンロード + src.Getpage(url, path) + // 色々の必須な編集 + src.Scanpage(path, eurl, cnf.Datapath) + // 新しいURLを表示 + fmt.Println(cnf.Domain + strings.Replace(path, cnf.Datapath, "", 1)) + } +} + +func main() { + // コンフィグファイル + cnf, err := src.Getconf() + if err != nil { + fmt.Println(err) + return + } + + // コマンドラインのパラメートル + args := os.Args + + if len(args) == 2 { + // バージョンを表示 + if args[1] == "-v" { + fmt.Println(common.GetSofname() + "-" + common.GetVersion()) + return + } else if args[1] == "-s" { // :9920でウェブサーバーを実行 + src.Serv(cnf, 9920) + } else if args[1] == "-h" { // ヘルプを表示 + help() + return + } else { + // コマンドラインでウェブサイトを保存 + saveurlcmd(args[1], cnf) + return + } + } else if len(args) == 3 && args[1] == "-s" { + // 好みなポート番号でウェブサーバーを実行 + // でも、数字じゃないかもしん + if port, err := strconv.Atoi(args[2]); err != nil { + fmt.Printf("%qは数字ではありません。\n", args[2]) + return + } else { + // OK、実行しよ〜 + src.Serv(cnf, port) + } + } else { + // パラメートルは不明の場合、ヘルプを表示 + help() + return + } +} diff --git a/src/config.go b/src/config.go new file mode 100644 index 0000000..f9d69dd --- /dev/null +++ b/src/config.go @@ -0,0 +1,71 @@ +package src + +import ( + "os" + "fmt" + "runtime" + "encoding/json" + "io/ioutil" + "errors" +) + +type Config struct { + Configpath, Webpath, Datapath, Domain, IP string +} + +var cnf Config + +func Getconf () (Config, error) { + // バイナリ、データ、及びFreeBSDとNetBSDの場合、コンフィグ + prefix := "/usr" + // BSDだけはただの/usrではない + if runtime.GOOS == "freebsd" || runtime.GOOS == "openbsd" { + prefix += "/local" + } else if runtime.GOOS == "netbsd" { + prefix += "/pkg" + } + + // コンフィグファイル + cnf.Configpath = "/etc/hozonsite/config.json" + cnf.Datapath = prefix + "/share/hozonsite" + + // また、FreeBSDとNetBSDだけは違う場所だ。OpenBSDは正しい場所 + // FreeBSD = /usr/local/etc/hozonsite/config.json + // NetBSD = /usr/pkg/etc/hozonsite/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("confif.jsonを開けられません:", err) + return cnf, errors.New( + "コンフィグファイルは " + cnf.Configpath + " に創作して下さい。", + ) + } + + var payload map[string]interface{} + json.Unmarshal(data, &payload) + if payload["webpath"] == nil { + return cnf, errors.New("「webpath」の値が設置していません。") + } + if payload["domain"] == nil { + return cnf, errors.New("「domain」の値が設置していません。") + } + if payload["ip"] == nil { + return cnf, errors.New("「ip」の値が設置していません。") + } + if _, err := os.Stat(payload["webpath"].(string)); err != nil { + fmt.Printf("%v\n", err) + return cnf, errors.New( + "mkdiorコマンドをつかって、 " + payload["webpath"].(string), + ) + } + cnf.Webpath = payload["webpath"].(string) // データパス + cnf.Domain = payload["domain"].(string) // ドメイン名 + cnf.IP = payload["ip"].(string) // IP + payload = nil // もういらなくなった + + return cnf, nil +} diff --git a/src/getpage.go b/src/getpage.go new file mode 100644 index 0000000..d4fea26 --- /dev/null +++ b/src/getpage.go @@ -0,0 +1,97 @@ +package src + +import ( + "os" + "fmt" + "net/http" + "io" + "regexp" + "strings" + + "golang.org/x/text/encoding/japanese" + "golang.org/x/text/transform" +) + +// URLでパラメートル(?、=等)がある場合 +func Stripurl (url string) string { + res := strings.ReplaceAll(url, "?", "") + res = strings.ReplaceAll(res, "=", "") + return res +} + +func Getpage (url string, path string) { + // ページを読み込む + curl, err := http.Get(url) + if err != nil { + fmt.Println("CURLエラー:", err) + return + } + // ソフトの終了する時に実行する + defer curl.Body.Close() + + // ページの内容を読み込む + body, err2 := io.ReadAll(curl.Body) + if err2 != nil { + fmt.Println("読込エラー:", err2) + return + } + + // Content-TypeヘッダーはUTF-8又は駄目のエンコーディングかの確認 + checkJis := `(?i))`).ReplaceAllString(string(fn), "", + ) + var noscript = regexp.MustCompile( + `()`).ReplaceAllString(string(script), "", + ) + var audio = regexp.MustCompile( + `()`).ReplaceAllString(string(noscript), "", + ) + var video = regexp.MustCompile( + `()`).ReplaceAllString(string(audio), "", + ) + var iframe = regexp.MustCompile( + `()`).ReplaceAllString(string(video), "", + ) + // 追加ダウンロード+ローカル化 + var ass = regexp.MustCompile( + // ルールに違反けど、長いからしょうがない・・・ + `(= 0; i-- { + if _, err := strconv.Atoi(pc[i]); err == nil { + return pc[i] + } + } + + return "" +} + +func handleStatic(path string, cnf Config, w http.ResponseWriter, r *http.Request) { + if !strings.HasSuffix(path, ".css") && + !strings.HasSuffix(path, ".png") && + !strings.HasSuffix(path, ".jpeg") && + !strings.HasSuffix(path, ".jpg") && + !strings.HasSuffix(path, ".webm") && + !strings.HasSuffix(path, ".gif") && + !strings.HasSuffix(path, ".js") { + http.NotFound(w, r) + return + } + + fpath := cnf.Datapath + "/archive/" + path + http.ServeFile(w, r, fpath) +} + +func handlePost(w http.ResponseWriter, r *http.Request, cnf Config) { + err := r.ParseForm() + if err != nil { + fmt.Println(err) + http.Redirect(w, r, "/", http.StatusSeeOther) + return + } + + // 言語変更 + if lang := r.PostFormValue("lang"); lang != "" { + http.SetCookie( + w, + &http.Cookie{Name: "lang", Value: lang, MaxAge: 31536000, Path: "/"}, + ) + http.Redirect(w, r, "/", http.StatusSeeOther) + return + } + + var exist []string + langu := initloc(r) + i18n, err := goliblocale.GetLocale(cnf.Webpath + "/locale/" + langu) + if err != nil { + fmt.Printf("liblocaleエラー:%v", err) + return + } + + if r.PostForm.Get("hozonsite") == "" { + data.Err = i18n["errfusei"] + ftmpl[0] = cnf.Webpath + "/view/404.html" + return + } + + url := r.PostForm.Get("hozonsite") + // HTTPかHTTPSじゃない場合 + if !Checkprefix(url) { + data.Err = i18n["errfuseiurl"] + ftmpl[0] = cnf.Webpath + "/view/404.html" + return + } + + eurl := Stripurl(url) + exist = Checkexist(eurl, cnf.Datapath) + if len(exist) == 0 || r.PostForm.Get("agree") == "1" { + path := Mkdirs(eurl, cnf.Datapath) + Getpage(url, path) + Scanpage(path, eurl, cnf.Datapath) + http.Redirect( + w, + r, + cnf.Domain + strings.Replace(path, cnf.Datapath, "", 1), + http.StatusSeeOther, + ) + return + } + + ftmpl[0] = cnf.Webpath + "/view/check.html" + data.Url = url + var existing []Exist + e := Exist{} + for _, ex := range exist { + ti, err := strconv.ParseInt(tspath(ex), 10, 64) + if err != nil { + fmt.Println(err) + http.Redirect(w, r, "/", http.StatusSeeOther) + return + } + + t := time.Unix(ti, 0) + e.Date = t.Format("2006年01月02日 15:04:05") + e.Url = strings.Replace(ex, cnf.Datapath, cnf.Domain, 1) + existing = append(existing, e) + } + + data.Ext = existing +} + +// ホームページ +func siteHandler (cnf Config) func (http.ResponseWriter, *http.Request) { + return func (w http.ResponseWriter, r *http.Request) { + ftmpl = []string{ + cnf.Webpath + "/view/index.html", + cnf.Webpath + "/view/header.html", + cnf.Webpath + "/view/footer.html", + } + + version := common.GetVersion() + data = &Page{ + Ver: version, + Ves: strings.ReplaceAll(version, ".", ""), + } + + lang := initloc(r) + data.Lan = lang + + i18n, err := goliblocale.GetLocale(cnf.Webpath + "/locale/" + lang) + if err != nil { + fmt.Printf("liblocaleエラー:%v", err) + return + } + data.i18n = i18n + ftmpl[0] = cnf.Webpath + "/view/index.html" + tmpl := template.Must(template.ParseFiles(ftmpl[0], ftmpl[1], ftmpl[2])) + + if r.Method == "POST" { + handlePost(w, r, cnf) + } + + tmpl = template.Must(template.ParseFiles(ftmpl[0], ftmpl[1], ftmpl[2])) + tmpl.Execute(w, data) + } +} + +// /api TODO +func apiHandler (cnf Config) func (http.ResponseWriter, *http.Request) { + return func (w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(200) + version := common.GetVersion() + + buf, _ := json.MarshalIndent( + &Stat{Url: cnf.Domain, Ver: version}, + "", + " ", + ) + _, _ = w.Write(buf) + } +} + +// /archive +func archiveHandler (cnf Config) func (http.ResponseWriter, *http.Request) { + return func (w http.ResponseWriter, r *http.Request) { + version := common.GetVersion() + + ftmpl := []string{ + cnf.Webpath + "/view/index.html", + cnf.Webpath + "/view/header.html", + cnf.Webpath + "/view/footer.html", + } + + data := &Page{Ver: version, Ves: strings.ReplaceAll(version, ".", "")} + lang := initloc(r) + data.Lan = lang + + i18n, err := goliblocale.GetLocale(cnf.Webpath + "/locale/" + lang) + if err != nil { + fmt.Printf("liblocaleエラー:%v", err) + return + } + data.i18n = i18n + ftmpl[0] = cnf.Webpath + "/view/index.html" + tmpl := template.Must(template.ParseFiles(ftmpl[0], ftmpl[1], ftmpl[2])) + path := strings.TrimPrefix(r.URL.Path, "/archive/") + + if strings.Contains(path, "/static/") { + handleStatic(path, cnf, w, r) + return + } + + pth := r.URL.Path + if !strings.HasSuffix(pth, "/") && + !strings.HasSuffix(pth, "index.html") { + pth += "/index.html" + } else if strings.HasSuffix(pth, "/") && + !strings.HasSuffix(pth, "index.html") { + pth += "index.html" + } + + file := cnf.Datapath + pth + if _, err := os.Stat(file); os.IsNotExist(err) { + http.Redirect(w, r, "/404", http.StatusSeeOther) + return + } + + bdy, err := os.ReadFile(file) + if err != nil { + http.Redirect(w, r, "/404", http.StatusSeeOther) + return + } + + data.Body = string(bdy) + tmpl = template.Must( + template.ParseFiles(cnf.Webpath + "/view/archive.html"), + ) + tmpl.Execute(w, data) + data = nil + } +} + +// サーバー +func Serv (cnf Config, port int) { + http.Handle( + "/static/", + http.StripPrefix("/static/", + http.FileServer(http.Dir(cnf.Webpath + "/static"))), + ) + + http.HandleFunc("/api/", apiHandler(cnf)) + http.HandleFunc("/archive/", archiveHandler(cnf)) + http.HandleFunc("/", siteHandler(cnf)) + + fmt.Println(fmt.Sprint( + "http://" + cnf.IP + ":", + port, + " でサーバーを実行中。終了するには、CTRL+Cを押して下さい。"), + ) + http.ListenAndServe(fmt.Sprint(cnf.IP + ":", port), nil) +} diff --git a/static/archive/.kara b/static/archive/.kara new file mode 100644 index 0000000..e69de29 diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..54ee352 Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/git.png b/static/git.png new file mode 100644 index 0000000..df3afde Binary files /dev/null and b/static/git.png differ diff --git a/static/logo.jpg b/static/logo.jpg new file mode 100644 index 0000000..15245f2 Binary files /dev/null and b/static/logo.jpg differ diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..a46b304 --- /dev/null +++ b/static/style.css @@ -0,0 +1,95 @@ +body { + background: #232629; + color: #fcfcfc; +} + +.headerimg { + border: 1px solid #dd0000; + box-shadow: 0px 0px 11px 5px #ff0000; +} + +.jswarning, .error { + color: rgb(252, 252, 252); + padding: 10px; + z-index: 5000; + position: fixed; + top: 0px; + left: 0px; + right: 0px; +} + +.jswarning { + background-color: rgb(170, 170, 0); + display: none; + border: 4px #dde22d ridge; +} + +.error { + background-color: rgb(170, 0, 0); + border: 4px #e22d2d ridge; +} + +a { + color: #ffeb3b; +} + +hr { + border-color: #dd0000; + box-shadow: 2px 2px 10px #ff0000; + width: 100%; +} + +.body, input { + color: #ea8181; + border: 1px #ff3b3b groove; +} + +.body { + margin: 0 auto; + max-width: 800px; + padding: 8px; + background-color: #320202; + box-shadow: 0px 0px 11px 5px #ff0000; +} + +.central { + margin: 0 auto; + max-width: 700px; +} + +input { + background-color: #600e0e; + font-size: 24px; + border-radius: 4px; +} + +input[type="text"] { + width: 99%; + max-width: 700px; + border-color: #ea8181; +} + +select { + background-color: #600e0e; + color: #ea8181; + font-size: 18px; + border-radius: 4px; + max-width: 700px; + border: 1px #ff3b3b groove; + padding: 8px; + width: 200px; +} + +select, input.langchange { + height: 35px; + vertical-align: middle; +} + +.submit, .footer, h1 { + margin-top: 32px; + text-align: center; +} + +input.langchange { + font-size: 24px; +} diff --git a/view/404.html b/view/404.html new file mode 100644 index 0000000..5ff36fc --- /dev/null +++ b/view/404.html @@ -0,0 +1,4 @@ +{{template "header" .}} + {{ .Err }}
+ {{.T "totop"}} +{{template "footer" .}} diff --git a/view/archive.html b/view/archive.html new file mode 100644 index 0000000..eb8bc64 --- /dev/null +++ b/view/archive.html @@ -0,0 +1,38 @@ + + + + + + + +
+ {{.T "archwhozonsite"}} hozonsite-{{ .Ver }}
+ {{.T "tophe"}} +
+
+ {{ .Body }} +
+ + diff --git a/view/check.html b/view/check.html new file mode 100644 index 0000000..1d5993e --- /dev/null +++ b/view/check.html @@ -0,0 +1,20 @@ +{{template "header" .}} +

{{.Url}}

+ {{.T "areadyhozon"}}
+ {{range $i, $e := .Ext}} + + {{$e.Date}} + +
+ {{end}} +

+ {{.T "willreallyhozon"}} +

+
+ + +
+ +
+
+{{template "footer" .}} diff --git a/view/footer.html b/view/footer.html new file mode 100644 index 0000000..ead91fa --- /dev/null +++ b/view/footer.html @@ -0,0 +1,12 @@ +{{define "footer"}} + + + + + +{{end}} diff --git a/view/header.html b/view/header.html new file mode 100644 index 0000000..d7b5fe9 --- /dev/null +++ b/view/header.html @@ -0,0 +1,32 @@ +{{define "header"}} + + + + + + + + {{.T "hozonsite"}}〜{{.T "top"}} + + + + +

+ {{.T +

+
+

+ {{.T "top"}} +

+
+
+ + +
+
+
+
+{{end}} diff --git a/view/index.html b/view/index.html new file mode 100644 index 0000000..465b674 --- /dev/null +++ b/view/index.html @@ -0,0 +1,9 @@ +{{template "header" .}} + {{.T "topwhatsave"}} +
+ +
+ +
+
+{{template "footer" .}}