Added dict with additional cards
This commit is contained in:
parent
181f3bc0aa
commit
88ea431a27
26 changed files with 232 additions and 35 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,5 +1,5 @@
|
|||
vendor
|
||||
go-mtg-vk
|
||||
*.swp
|
||||
hosts
|
||||
.idea
|
||||
.venv
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
FROM golang:1.15.4-alpine3.12
|
||||
|
||||
COPY . /go/src/go-mtg-vk
|
||||
WORKDIR /go/src/go-mtg-vk
|
||||
WORKDIR /go/src/go-mtg-vk/cmd/go-mtg-vk
|
||||
RUN go install
|
||||
WORKDIR /go/bin
|
||||
RUN mkdir logs
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import (
|
|||
"os"
|
||||
"time"
|
||||
|
||||
"gitlab.com/flygrounder/go-mtg-vk/vk"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gitlab.com/flygrounder/go-mtg-vk/internal/vk"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
@ -17,5 +17,5 @@ func main() {
|
|||
log.SetOutput(logFile)
|
||||
r := gin.Default()
|
||||
r.POST("callback/message", vk.HandleMessage)
|
||||
_ = r.Run(":80")
|
||||
_ = r.Run(":8000")
|
||||
}
|
||||
16
docker-compose-dev.yaml
Normal file
16
docker-compose-dev.yaml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
version: "3.3"
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
environment:
|
||||
- VK_TOKEN
|
||||
- VK_SECRET_KEY
|
||||
- VK_GROUP_ID
|
||||
- VK_CONFIRMATION_STRING
|
||||
|
||||
ports:
|
||||
- "127.0.0.1:8888:8000"
|
||||
restart: "always"
|
||||
redis:
|
||||
image: "redis:6.0.9"
|
||||
restart: "always"
|
||||
|
|
@ -9,7 +9,7 @@ services:
|
|||
- VK_CONFIRMATION_STRING
|
||||
|
||||
ports:
|
||||
- "127.0.0.1:8888:80"
|
||||
- "127.0.0.1:8888:8000"
|
||||
restart: "always"
|
||||
redis:
|
||||
image: "redis:6.0.9"
|
||||
|
|
|
|||
1
go.mod
1
go.mod
|
|
@ -14,6 +14,7 @@ require (
|
|||
github.com/onsi/gomega v1.7.1 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/stretchr/testify v1.5.1
|
||||
github.com/texttheater/golang-levenshtein/levenshtein v0.0.0-20200805054039-cae8b0eaed6c
|
||||
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da // indirect
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 // indirect
|
||||
golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c // indirect
|
||||
|
|
|
|||
3
go.sum
3
go.sum
|
|
@ -52,6 +52,9 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
|
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/texttheater/golang-levenshtein v1.0.1 h1:+cRNoVrfiwufQPhoMzB6N0Yf/Mqajr6t1lOv8GyGE2U=
|
||||
github.com/texttheater/golang-levenshtein/levenshtein v0.0.0-20200805054039-cae8b0eaed6c h1:HelZ2kAFadG0La9d+4htN4HzQ68Bm2iM9qKMSMES6xg=
|
||||
github.com/texttheater/golang-levenshtein/levenshtein v0.0.0-20200805054039-cae8b0eaed6c/go.mod h1:JlzghshsemAMDGZLytTFY8C1JQxQPhnatWqNwUXjggo=
|
||||
github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ func FormatCardPrices(name string, prices []CardPrice) string {
|
|||
message := fmt.Sprintf("Оригинальное название: %v\n", name)
|
||||
message += fmt.Sprintf("Результатов: %v\n", len(prices))
|
||||
for i, v := range prices {
|
||||
message += fmt.Sprintf("%v. %v", i + 1, v.Format())
|
||||
message += fmt.Sprintf("%v. %v", i+1, v.Format())
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@ package cardsinfo
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"gitlab.com/flygrounder/go-mtg-vk/internal/dicttranslate"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
|
@ -18,9 +20,13 @@ func GetNameByCardId(set string, number string) string {
|
|||
return GetCardByUrl(path)
|
||||
}
|
||||
|
||||
func GetOriginalName(name string) string {
|
||||
func GetOriginalName(name string, dict io.Reader) string {
|
||||
path := ScryfallUrl + "/cards/named?fuzzy=" + ApplyFilters(name)
|
||||
return GetCardByUrl(path)
|
||||
result := GetCardByUrl(path)
|
||||
if result == "" && dict != nil {
|
||||
result, _ = dicttranslate.FindFromReader(name, dict, 5)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func ApplyFilters(name string) string {
|
||||
|
|
@ -2,36 +2,37 @@ package cardsinfo
|
|||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetCardByStringFull(t *testing.T) {
|
||||
name := GetOriginalName("Шок")
|
||||
name := GetOriginalName("Шок", nil)
|
||||
assert.Equal(t, "Shock", name)
|
||||
}
|
||||
|
||||
func TestGetCardByStringSplit(t *testing.T) {
|
||||
name := GetOriginalName("commit")
|
||||
name := GetOriginalName("commit", nil)
|
||||
assert.Equal(t, "Commit // Memory", name)
|
||||
}
|
||||
|
||||
func TestGetCardByStringDouble(t *testing.T) {
|
||||
name := GetOriginalName("Legion's landing")
|
||||
name := GetOriginalName("Legion's landing", nil)
|
||||
assert.Equal(t, "Legion's Landing | Adanto, the First Fort", name)
|
||||
}
|
||||
|
||||
func TestGetCardByStringPrefix(t *testing.T) {
|
||||
name := GetOriginalName("Тефери, герой")
|
||||
name := GetOriginalName("Тефери, герой", nil)
|
||||
assert.Equal(t, "Teferi, Hero of Dominaria", name)
|
||||
}
|
||||
|
||||
func TestGetCardByStringEnglish(t *testing.T) {
|
||||
name := GetOriginalName("Teferi, Hero of Dominaria")
|
||||
name := GetOriginalName("Teferi, Hero of Dominaria", nil)
|
||||
assert.Equal(t, "Teferi, Hero of Dominaria", name)
|
||||
}
|
||||
|
||||
func TestGetCardByStringWrong(t *testing.T) {
|
||||
name := GetOriginalName("fwijefiwjfew")
|
||||
name := GetOriginalName("fwijefiwjfew", nil)
|
||||
assert.Equal(t, "", name)
|
||||
}
|
||||
|
||||
|
|
@ -44,3 +45,9 @@ func TestGetCardBySetIdWrong(t *testing.T) {
|
|||
name := GetNameByCardId("DOM", "1207")
|
||||
assert.Equal(t, "", name)
|
||||
}
|
||||
|
||||
func TestGetCardByStringDict(t *testing.T) {
|
||||
dictContent := "{\"n0suchc8rdc8n3x1s1\":\"Success\"}"
|
||||
name := GetOriginalName("n0suchc8rdc8n3x1s1", strings.NewReader(dictContent))
|
||||
assert.Equal(t, "Success", name)
|
||||
}
|
||||
|
|
@ -71,7 +71,7 @@ func GetPricesTcg(name string) ([]CardPrice, error) {
|
|||
if card.Prices.USD == "" && card.Prices.USDFoil == "" {
|
||||
continue
|
||||
}
|
||||
cardPrice := &TcgCardPrice {
|
||||
cardPrice := &TcgCardPrice{
|
||||
Edition: edition,
|
||||
Price: card.Prices.USD,
|
||||
PriceFoil: card.Prices.USDFoil,
|
||||
23
internal/dicttranslate/find.go
Normal file
23
internal/dicttranslate/find.go
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package dicttranslate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
func find(query string, dict map[string]string, maxDist int) (string, bool) {
|
||||
var keys []string
|
||||
for i := range dict {
|
||||
keys = append(keys, i)
|
||||
}
|
||||
key, f := match(query, keys, maxDist)
|
||||
return dict[key], f
|
||||
}
|
||||
|
||||
func FindFromReader(query string, reader io.Reader, maxDist int) (string, bool) {
|
||||
content, _ := ioutil.ReadAll(reader)
|
||||
dict := map[string]string{}
|
||||
_ = json.Unmarshal(content, &dict)
|
||||
return find(query, dict, maxDist)
|
||||
}
|
||||
33
internal/dicttranslate/find_test.go
Normal file
33
internal/dicttranslate/find_test.go
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package dicttranslate
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFindEmpty(t *testing.T) {
|
||||
dict := map[string]string{}
|
||||
_, f := find("", dict, 0)
|
||||
assert.False(t, f)
|
||||
}
|
||||
|
||||
func TestFindEntry(t *testing.T) {
|
||||
dict := map[string]string{
|
||||
"entry": "value",
|
||||
}
|
||||
val, f := find("entry", dict, 0)
|
||||
assert.True(t, f)
|
||||
assert.Equal(t, "value", val)
|
||||
}
|
||||
|
||||
func TestFindFromReaderFail(t *testing.T) {
|
||||
_, f := FindFromReader("entry", strings.NewReader("{}"), 0)
|
||||
assert.False(t, f)
|
||||
}
|
||||
|
||||
func TestFindFromReaderSuccess(t *testing.T) {
|
||||
value, f := FindFromReader("entry", strings.NewReader("{\"entry\":\"value\"}"), 0)
|
||||
assert.True(t, f)
|
||||
assert.Equal(t, "value", value)
|
||||
}
|
||||
21
internal/dicttranslate/match.go
Normal file
21
internal/dicttranslate/match.go
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package dicttranslate
|
||||
|
||||
import "github.com/texttheater/golang-levenshtein/levenshtein"
|
||||
|
||||
func match(query string, opts []string, maxDist int) (string, bool) {
|
||||
bestInd := -1
|
||||
bestDist := 0
|
||||
for i, s := range opts {
|
||||
cfg := levenshtein.DefaultOptions
|
||||
cfg.SubCost = 1
|
||||
dist := levenshtein.DistanceForStrings([]rune(s), []rune(query), cfg)
|
||||
if dist <= maxDist && (bestInd == -1 || dist < bestDist) {
|
||||
bestInd = i
|
||||
bestDist = dist
|
||||
}
|
||||
}
|
||||
if bestInd == -1 {
|
||||
return "", false
|
||||
}
|
||||
return opts[bestInd], true
|
||||
}
|
||||
52
internal/dicttranslate/match_test.go
Normal file
52
internal/dicttranslate/match_test.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package dicttranslate
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMatch(t *testing.T) {
|
||||
type testCase struct {
|
||||
name string
|
||||
query string
|
||||
opts []string
|
||||
shouldFind bool
|
||||
match string
|
||||
}
|
||||
tests := []testCase{
|
||||
{
|
||||
name: "No options",
|
||||
query: "opt",
|
||||
opts: []string{},
|
||||
shouldFind: false,
|
||||
},
|
||||
{
|
||||
name: "Match one",
|
||||
query: "option",
|
||||
opts: []string{"opt1on"},
|
||||
shouldFind: true,
|
||||
match: "opt1on",
|
||||
},
|
||||
{
|
||||
name: "Match exact",
|
||||
query: "opt1on",
|
||||
opts: []string{"option", "opt1on"},
|
||||
shouldFind: true,
|
||||
match: "opt1on",
|
||||
},
|
||||
{
|
||||
name: "Do not match bad options",
|
||||
query: "random",
|
||||
opts: []string{"option", "opt1on"},
|
||||
shouldFind: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
val, f := match(test.query, test.opts, 1)
|
||||
assert.Equal(t, test.shouldFind, f)
|
||||
assert.Equal(t, test.match, val)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -4,13 +4,16 @@ import (
|
|||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"gitlab.com/flygrounder/go-mtg-vk/caching"
|
||||
"gitlab.com/flygrounder/go-mtg-vk/cardsinfo"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gitlab.com/flygrounder/go-mtg-vk/internal/caching"
|
||||
"gitlab.com/flygrounder/go-mtg-vk/internal/cardsinfo"
|
||||
)
|
||||
|
||||
var dictPath = "./assets/additional_cards.json"
|
||||
|
||||
func HandleMessage(c *gin.Context) {
|
||||
var req MessageRequest
|
||||
_ = c.BindJSON(&req)
|
||||
|
|
@ -78,7 +81,8 @@ func getCardNameByCommand(command string) (string, error) {
|
|||
number := split[2]
|
||||
name = cardsinfo.GetNameByCardId(set, number)
|
||||
default:
|
||||
name = cardsinfo.GetOriginalName(command)
|
||||
dict, _ := os.Open(dictPath)
|
||||
name = cardsinfo.GetOriginalName(command, dict)
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
31
scripts/spoiler_fetcher.py
Normal file
31
scripts/spoiler_fetcher.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
from json import dumps
|
||||
|
||||
import requests
|
||||
from lxml import etree
|
||||
|
||||
URL_TEMPLATE = "https://magic.wizards.com/{}/articles/archive/card-image-gallery/{}"
|
||||
OUTPUT_FILE_TEMPLATE = "{}.json"
|
||||
|
||||
|
||||
def get_card_names(language, set_name):
|
||||
spoiler_url = URL_TEMPLATE.format(language, set_name)
|
||||
response = requests.get(spoiler_url)
|
||||
dom = etree.HTML(response.content.decode())
|
||||
card_names = dom.xpath('//div[@class="resizing-cig"]//p/text()')
|
||||
return [str(name).strip() for name in card_names]
|
||||
|
||||
|
||||
def match_names(keys, values):
|
||||
return dict(zip(keys, values))
|
||||
|
||||
|
||||
set_name = input("Введите сет: ")
|
||||
|
||||
russian_names = get_card_names("ru", set_name)
|
||||
english_names = get_card_names("en", set_name)
|
||||
|
||||
match = match_names(russian_names, english_names)
|
||||
print(match)
|
||||
|
||||
with open(OUTPUT_FILE_TEMPLATE.format(set_name), 'w') as output:
|
||||
output.write(dumps(match))
|
||||
Loading…
Add table
Add a link
Reference in a new issue