Added dict with additional cards

This commit is contained in:
Artyom Belousov 2021-02-03 19:09:08 +03:00
parent 181f3bc0aa
commit 88ea431a27
26 changed files with 232 additions and 35 deletions

2
.gitignore vendored
View file

@ -1,5 +1,5 @@
vendor
go-mtg-vk
*.swp
hosts
.idea
.venv

View file

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

View file

@ -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
View 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"

View file

@ -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
View file

@ -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
View file

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

View file

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

View file

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

View file

@ -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)
}

View file

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

View 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)
}

View 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)
}

View 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
}

View 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)
})
}
}

View file

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

View 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))