SVNからのミラー

This commit is contained in:
2026-01-06 20:42:18 +09:00
commit f14261d8d1
14 changed files with 674 additions and 0 deletions

18
CHANGELOG.md Normal file
View File

@@ -0,0 +1,18 @@
# 1.1.0 (2024/06/29)
* GNU Make → BSD Make
* GPLv2 → ISC
* 「--no-」のオプションの変更
* help → usage
* 「同駅内徒歩」表示のバグの修正
* 「gookit/color」という従属ソフトの取消
* 「当駅始発」がなければ、全角空白文字で使って「◯◯線」と「◯◯行」を分けて
# 1.0.2 (2023/10/23)
* ヤフー社はHTMLをちょっと更新されたから、乗換を修正する事が必要となった
# 1.0.1 (2023/06/23)
* -vを修正
* 電車・バス・空路の表示
# 1.0.0 (2023/06/22)
* 最初リリース

13
LICENSE.txt Normal file
View File

@@ -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.

84
Makefile Normal file
View File

@@ -0,0 +1,84 @@
UNAME_S != uname -s
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"
PREFIX = /usr/local
MANPREFIX = ${PREFIX}/share/man
.if ${UNAME_S} == "OpenBSD"
MANPREFIX = ${PREFIX}/man
.elif ${UNAME_S} == "Linux"
PREFIX = /usr
MANPREFIX = ${PREFIX}/share/man
.endif
CC = CGO_ENABLED=0 go build
RELEASE = -ldflags="-s -w" -buildvcs=false
all:
${CC} ${RELEASE} -o ${NAME}
release:
mkdir -p release/bin
env GOOS=linux GOARCH=amd64 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-linux-amd64
env GOOS=linux GOARCH=arm64 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-linux-arm64
env GOOS=linux GOARCH=riscv64 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-linux-riscv64
env GOOS=linux GOARCH=386 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-linux-i386
env GOOS=linux GOARCH=ppc64 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-linux-ppc64
env GOOS=linux GOARCH=mips64 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-linux-mips64
env GOOS=openbsd GOARCH=amd64 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-openbsd-amd64
env GOOS=openbsd GOARCH=386 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-openbsd-i386
env GOOS=openbsd GOARCH=arm64 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-openbsd-arm64
env GOOS=freebsd GOARCH=amd64 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-freebsd-amd64
env GOOS=freebsd GOARCH=386 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-freebsd-i386
env GOOS=freebsd GOARCH=arm64 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-freebsd-arm64
env GOOS=freebsd GOARCH=riscv64 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-freebsd-riscv64
env GOOS=netbsd GOARCH=amd64 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-netbsd-amd64
env GOOS=netbsd GOARCH=386 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-netbsd-i386
env GOOS=netbsd GOARCH=arm64 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-netbsd-arm64
env GOOS=illumos GOARCH=amd64 ${CC} ${RELEASE} -o \
release/bin/${NAME}-${VERSION}-illumos-amd64
clean:
rm -f ${NAME}
dist:
mkdir -p ${NAME}-${VERSION} release/src
cp -R LICENSE.txt Makefile README.md CHANGELOG.md\
${NAME}.1 main.go src go.mod go.sum ${NAME}-${VERSION}
tar zcfv release/src/${NAME}-${VERSION}.tar.gz ${NAME}-${VERSION}
rm -rf ${NAME}-${VERSION}
man:
mkdir -p release/man
sed "s/VERSION/${VERSION}/g" < ${NAME}.1 > release/man/${NAME}-${VERSION}.1
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
uninstall:
rm -f ${DESTDIR}${PREFIX}/bin/${NAME}\
${DESTDIR}${MANPREFIX}/man1/${NAME}.1
.PHONY: all release clean dist man install uninstall

18
README.md Normal file
View File

@@ -0,0 +1,18 @@
# 乗換
CLIでの路線情報
## インストールする方法
```sh
cd norikae
make
doas make install
```
### Linuxの場合
```sh
cd norikae
bmake
doas bmake install
```
![](スクリーンショット 2026-01-06 203908.png)

23
go.mod Normal file
View File

@@ -0,0 +1,23 @@
module 076/norikae
go 1.20
require github.com/gocolly/colly v1.2.0
require (
github.com/PuerkitoBio/goquery v1.8.1 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/antchfx/htmlquery v1.3.0 // indirect
github.com/antchfx/xmlquery v1.3.17 // indirect
github.com/antchfx/xpath v1.2.4 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.3.1 // indirect
github.com/kennygrant/sanitize v1.2.4 // indirect
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
github.com/stretchr/testify v1.8.4 // indirect
github.com/temoto/robotstxt v1.1.2 // indirect
golang.org/x/net v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
)

76
go.sum Normal file
View File

@@ -0,0 +1,76 @@
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/antchfx/htmlquery v1.3.0 h1:5I5yNFOVI+egyia5F2s/5Do2nFWxJz41Tr3DyfKD25E=
github.com/antchfx/htmlquery v1.3.0/go.mod h1:zKPDVTMhfOmcwxheXUsx4rKJy8KEY/PU6eXr/2SebQ8=
github.com/antchfx/xmlquery v1.3.17 h1:d0qWjPp/D+vtRw7ivCwT5ApH/3CkQU8JOeo3245PpTk=
github.com/antchfx/xmlquery v1.3.17/go.mod h1:Afkq4JIeXut75taLSuI31ISJ/zeq+3jG7TunF7noreA=
github.com/antchfx/xpath v1.2.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
github.com/antchfx/xpath v1.2.4 h1:dW1HB/JxKvGtJ9WyVGJ0sIoEcqftV3SqIstujI+B9XY=
github.com/antchfx/xpath v1.2.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gocolly/colly v1.2.0 h1:qRz9YAn8FIH0qzgNUw+HT9UN7wm1oF9OBAilwEWpyrI=
github.com/gocolly/colly v1.2.0/go.mod h1:Hof5T3ZswNVsOHYmba1u03W65HDWgpV5HifSuueE0EA=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o=
github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/temoto/robotstxt v1.1.2 h1:W2pOjSJ6SWvldyEuiFXNxz3xZ8aiWX5LbfDiOFd7Fxg=
github.com/temoto/robotstxt v1.1.2/go.mod h1:+1AmkuG3IYkh1kv0d2qEB9Le88ehNO0zwOr3ujewlOo=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

87
main.go Normal file
View File

@@ -0,0 +1,87 @@
package main
import (
"fmt"
"os"
"time"
"076/norikae/src"
)
var sofname = "norikae"
var version = "1.1.0"
var avalopt = "ABEfFjmnrStX"
func usage() {
fmt.Printf("%s-%s\nusage: %s [-%s] [string]\n", sofname, version, sofname, avalopt)
}
func main() {
var opts src.Opts
// デフォルトな値
t := time.Now()
opts.Date = t.Format("2006-01-02")
opts.Time = t.Format("15:04")
opts.Mode = "0"
opts.Route = "0"
opts.NoAirplane = true
opts.NoShinkansen = true
opts.NoExpress = true
opts.NoExpressBus = true
opts.NoBus = true
opts.NoFairy = true
if len(os.Args) == 1 {
usage()
return
}
var foundf, foundt bool
for _, v := range os.Args {
if (v == "-f") { foundf = true }
if (v == "-t") { foundt = true }
}
if !foundf || !foundt {
usage()
return
}
for i := 1; i < len(os.Args); i++ {
if os.Args[i] == "-f" { opts.From = os.Args[i+1] }
if os.Args[i] == "-t" { opts.To = os.Args[i+1] }
if os.Args[i] == "-n" { opts.Date = os.Args[i+1] }
if os.Args[i] == "-j" { opts.Time = os.Args[i+1] }
if os.Args[i] == "-m" { opts.Mode = os.Args[i+1] }
if os.Args[i] == "-r" { opts.Route = os.Args[i+1] }
if os.Args[i] == "-A" {
opts.NoAirplane = false
}
if os.Args[i] == "-S" {
opts.NoShinkansen = false
}
if os.Args[i] == "-E" {
opts.NoExpress = false
}
if os.Args[i] == "-X" {
opts.NoExpressBus = false
}
if os.Args[i] == "-B" {
opts.NoBus = false
}
if os.Args[i] == "-F" {
opts.NoFairy = false
}
}
gurl, err := src.GetUrl(opts)
if err != nil {
fmt.Println(err)
return
}
route := src.Scrape(gurl)
src.Render(route)
}

52
norikae.1 Normal file
View File

@@ -0,0 +1,52 @@
.TH 乗換 1 norikae\-VERSION
.SH ソフト名
乗換 - CLIでの路線情報
.SH 概要
.B norikae
[\fI\,オプション\/\fR] [\fI\,ほげほげ\/\fR]
.SH 説明
.PP
CLIでの路線情報
.SH 必須のオプション
.TP
\fB\-f [駅名]\fR
出社駅、例:秋葉原、渋谷、大手町(東京)
.TP
\fB\-t [駅名]\fR
到着駅、例:秋葉原、渋谷、大手町(東京)
.SH 任意のオプション
.TP
\fB\-n [YYYY-MM-DD]\fR
年月日、ハイフン(-)で分けて、デフォルト=今
.TP
\fB\-j [HH:MM]\fR
時間、デフォルト=今
.TP
\fB\-m [数字]\fR
0 = 出発、1 = 指定なし、2 = 終電、3 = 始発、4 = 到着、デフォルト0
.TP
\fB\-r [数字]\fR
0 = 到着が早い順、1 = 料金が高い順、2 = 乗り換え回数順、デフォルト0
.TP
\fB\-A\fR
空路を省く
.TP
\fB\-S\fR
新幹線を省く
.TP
\fB\-E\fR
有料特急を省く
.TP
\fB\-X\fR
高速バスを省く
.TP
\fB\-B\fR
路線/連絡バスを省く
.TP
\fB\-F\fR
フェリーを省く
.SH バグ報告
.PP
バグは下記のURLまでご報告下さい
.br
https://gitler.moe/suwako/norikae/issues

46
src/geturl.go Executable file
View File

@@ -0,0 +1,46 @@
package src
import (
"strings"
"net/url"
)
func b2s (val bool) string {
if val { return "1" }
return "0"
}
func GetUrl (f Opts) (string, error) {
date := strings.Split(f.Date, "-")
year := date[0]
month := date[1]
day := date[2]
hour := strings.Split(f.Time, ":")[0]
minute := strings.Split(f.Time, ":")[1]
m1 := string(minute[0])
m2 := string(minute[1])
curl, err := url.Parse(
"https://transit.yahoo.co.jp/search/result" +
"?from=" + url.QueryEscape(f.From) +
"&to=" + url.QueryEscape(f.To) +
"&y=" + year +
"&m=" + month +
"&d=" + day +
"&hh=" + hour +
"&m1=" + m1 +
"&m2=" + m2 +
"&type=" + f.Mode +
"&ticket=ic&expkind=1&userpass=1&ws=" + f.Route +
"&al=" + b2s(f.NoAirplane) +
"&shin=" + b2s(f.NoShinkansen) +
"&ex=" + b2s(f.NoExpress) +
"&hb=" + b2s(f.NoExpressBus) +
"&lb=" + b2s(f.NoBus) +
"&sr=" + b2s(f.NoFairy))
if err != nil {
return "", nil
}
return curl.String(), nil
}

65
src/render.go Executable file
View File

@@ -0,0 +1,65 @@
package src
import (
"fmt"
)
var r, g, b uint8
var col string
func getFares(v Station, k int) {
for i, fare := range v.Fares {
if k != i {
continue
}
col = fare.Color
fmt.Sscanf(col, "%2x%2x%2x", &r, &g, &b)
text := fare.Train
if fare.Platform != "" {
text += "\n" + fare.Platform
}
c := fmt.Sprintf("\x1b[38;2;%d;%d;%dm%s\x1b[0m", r, g, b, text)
fmt.Println(c)
}
}
func Render (route []Route) {
col = "fcfcfc"
fmt.Sscanf("ff7e56", "%2x%2x%2x", &r, &g, &b)
b1 := fmt.Sprintf("\x1b[38;2;%d;%d;%dm%s\x1b[0m", r, g, b, "早")
fmt.Sscanf("60bddb", "%2x%2x%2x", &r, &g, &b)
b2 := fmt.Sprintf("\x1b[38;2;%d;%d;%dm%s\x1b[0m", r, g, b, "楽")
fmt.Sscanf("fab60a", "%2x%2x%2x", &r, &g, &b)
b3 := fmt.Sprintf("\x1b[38;2;%d;%d;%dm%s\x1b[0m", r, g, b, "安")
fmt.Sscanf(col, "%2x%2x%2x", &r, &g, &b)
for key, value := range route {
fmt.Printf("\x1b[1;35m# ルート%d\x1b[0m\n", key+1)
badges := ""
for _, badge := range value.Badges {
if badge == 1 { badges += "〈" + b1 + "〉" }
if badge == 2 { badges += "〈" + b2 + "〉" }
if badge == 3 { badges += "〈" + b3 + "〉" }
}
fmt.Println(
value.Time + " (" + value.Duration + "), " +
value.Fare + ", 乗換数:" + value.TransitCunt + " " + badges,
)
for k, v := range value.Stations {
fmt.Println(v.Time + " " + v.Name)
getFares(v, k)
}
fmt.Println("")
}
}

104
src/routedetail.go Executable file
View File

@@ -0,0 +1,104 @@
package src
import (
"strings"
"regexp"
"github.com/gocolly/colly"
)
func getSummary(e *colly.HTMLElement) Route {
r := Route{}
if e.Attr("class") == "icnPriTime" { r.Badges = append(r.Badges, 1) }
if e.Attr("class") == "icnPriFare" { r.Badges = append(r.Badges, 2) }
if e.Attr("class") == "icnPriTrans" { r.Badges = append(r.Badges, 3) }
return r
}
func handleFare(el *colly.HTMLElement, f Fare, s Stop) Fare {
fixTrain := strings.ReplaceAll(
el.ChildText("li.transport div"), "[train]", "【電車】",
)
fixBus := strings.ReplaceAll(fixTrain, "[bus]", "【バス】")
fixAir := strings.ReplaceAll(fixBus, "[air]", "【空路】")
fixEki := strings.ReplaceAll(fixAir, "当駅始発", "【当駅始発】")
pattern := regexp.MustCompile(`(^.*線)(.*[行|方面]$)`)
fixeki := pattern.ReplaceAllString(fixEki, "$1 $2")
f.Train = fixeki
f.Platform = el.ChildText("li.platform")
f.Color = strings.ReplaceAll(el.ChildAttr("span", "style"), "border-color:#", "")
el.ForEach("li.stop ul", func (js int, els *colly.HTMLElement) {
s.Time = els.ChildText("li dl dt")
s.Name = strings.ReplaceAll(els.ChildText("li dl dd"), "○", "")
f.Stops = append(f.Stops, s)
})
return f
}
func handleWalk(el *colly.HTMLElement, f Fare) Fare {
f.Train = strings.ReplaceAll(
el.ChildText("li.transport"), "[line][walk]", "",
)
f.Platform = ""
f.Color = "a8a8a8"
return f
}
func getRouteDetail(e *colly.HTMLElement) Route {
r := Route{}
onDivs := "div.routeSummary div ul.priority li span"
e.ForEach(onDivs, func(i int, el *colly.HTMLElement) {
summary := getSummary(el)
r.Badges = append(r.Badges, summary.Badges...)
})
base := e.ChildText("ul.summary li.time span")
time := strings.ReplaceAll(base, e.ChildText("ul.summary li.time span.small"), "")
time2 := strings.Split(time, "着")
r.Time = time2[0] + "着"
durabase := e.ChildText("ul.summary li.time")
durasi := strings.Index(durabase, "着") + len("着")
duraei := strings.Index(durabase[durasi:], "分") + len("分") + durasi
r.Duration = durabase[durasi:duraei]
r.TransitCunt = strings.ReplaceAll(
e.ChildText("ul.summary li.transfer"), "乗換:", "",
)
r.Fare = strings.ReplaceAll(
e.ChildText("ul.summary li.fare"), "[priic]IC優先", "",
)
onDivs = "div.routeDetail div.station"
e.ForEach(onDivs, func (j int, el *colly.HTMLElement) {
station := Station{}
station.Time = el.ChildText("ul.time li")
if el.ChildText("p.icon span") == "[dep]" { station.Time += "発" }
if el.ChildText("p.icon span") == "[arr]" { station.Time += "着" }
station.Name = el.ChildText("dl dt a")
fares := []Fare{}
onDivs = "div.routeDetail div.fareSection div.access"
e.ForEach(onDivs, func (jf int, elf *colly.HTMLElement) {
fare := Fare{}
fare = handleFare(elf, fare, Stop{})
fares = append(fares, fare)
})
onDivs = "div.routeDetail div.walk ul.info"
e.ForEach(onDivs, func (jw int, elw *colly.HTMLElement) {
fare := Fare{}
fare = handleWalk(elw, fare)
fares = append(fares, fare)
})
station.Fares = fares
r.Stations = append(r.Stations, station)
})
return r
}

64
src/scrape.go Executable file
View File

@@ -0,0 +1,64 @@
package src
import (
"log"
"net/http"
"time"
"net"
"fmt"
"github.com/gocolly/colly"
)
func Scrape (gurl string) []Route {
ua := "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
"AppleWebKit/537.36 (KHTML, like Gecko) " +
"Chrome/110.0.0.0 Safari/537.36"
sc := colly.NewCollector(
colly.AllowURLRevisit(),
colly.Async(true),
)
sc.WithTransport(&http.Transport {
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
})
sc.OnRequest(func(r *colly.Request) {
r.Headers.Set("User-Agent", ua)
r.Headers.Set(
"Accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
)
r.Headers.Set("Accept-Language", "en-US,en;q=0.5")
})
sc.OnError(func(_ *colly.Response, err error) {
log.Fatal("エラー:", err)
})
var routeArr []Route
for i := 1; i <= 3; i++ {
route := fmt.Sprintf("div#route%02d", i)
sc.OnHTML("div.elmRouteDetail " + route, func (e *colly.HTMLElement) {
Routes := getRouteDetail(e)
routeArr = append(routeArr, Routes)
})
}
sc.Visit(gurl)
sc.Wait()
return routeArr
}

24
src/structs.go Executable file
View File

@@ -0,0 +1,24 @@
package src
type (
Opts struct {
From, To, Date, Time, Mode, Route string
NoAirplane, NoShinkansen, NoExpress, NoExpressBus, NoBus, NoFairy bool
}
Route struct {
Time, Duration, TransitCunt, Fare string
Badges []int
Stations []Station
}
Station struct {
Time, Name string
Fares []Fare
}
Fare struct {
Train, Color, Platform string
Stops []Stop
}
Stop struct {
Time, Name string
}
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 KiB