mirror of
https://github.com/ultrasn0w/huso.git
synced 2025-12-16 22:59:52 +01:00
Compare commits
39 Commits
f7c331c945
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17a754b918 | ||
|
|
730f91e74e | ||
|
|
dbd34abea1 | ||
|
|
beed95eed9 | ||
|
|
074a4a88f0 | ||
|
|
fa765859e4 | ||
|
|
1f59f13bfc | ||
|
|
92660df667 | ||
|
|
db4ca8e4cf | ||
|
|
13b2335ae8 | ||
|
|
1bb8536334 | ||
|
|
6a2e573828 | ||
|
|
7185544e03 | ||
|
|
7fe4181c72 | ||
|
|
3771b1d2c4 | ||
|
|
d54ed135e3 | ||
|
|
ec6ed3cc63 | ||
|
|
2e5b45a699 | ||
|
|
10a563bb23 | ||
|
|
ecba4d68e6 | ||
|
|
1a075e79ff | ||
|
|
12c69818ce | ||
|
|
3efd003424 | ||
|
|
fd0f8bc8e2 | ||
|
|
0417ceb1f9 | ||
|
|
aec582ff8e | ||
|
|
5d1efd6bcf | ||
|
|
6f37daedfe | ||
|
|
8df72d6f18 | ||
|
|
d87b658837 | ||
|
|
be04fb92e5 | ||
|
|
f968c1b98e | ||
|
|
fd84193d9d | ||
|
|
f078c93b9e | ||
|
|
cc525f2460 | ||
|
|
da474ecede | ||
|
|
0461ec1717 | ||
|
|
022ff8d0f9 | ||
|
|
2b12e63637 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -16,3 +16,4 @@
|
|||||||
|
|
||||||
huso
|
huso
|
||||||
nuts/*
|
nuts/*
|
||||||
|
mm.cred
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -16,13 +16,15 @@ Hanami's universeller Serien Organizer
|
|||||||
| - | - | - | - | - | - | - |
|
| - | - | - | - | - | - | - |
|
||||||
| GET | /api/auth/{user} | Test für Authentifizierung | (status code) | {user} = MAL username | X-HUSO-AUTH | |
|
| GET | /api/auth/{user} | Test für Authentifizierung | (status code) | {user} = MAL username | X-HUSO-AUTH | |
|
||||||
| POST | /api/register | Registrieren | RegisterData JSON | | | RegisterData JSON |
|
| POST | /api/register | Registrieren | RegisterData JSON | | | RegisterData JSON |
|
||||||
| DELETE | /api/register | User löschen | RegisterData JSON | | | RegisterData JSON |
|
| PATCH | /api/register | Registrierung bearbeiten | RegisterData JSON | | X-HUSO-AUTH | RegisterData JSON |
|
||||||
|
| DELETE | /api/register | User löschen | RegisterData JSON | | X-HUSO-AUTH | RegisterData JSON |
|
||||||
|
|
||||||
_RegisterData_
|
_RegisterData_
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"username": "TESTUSERNAME",
|
"username": "TESTUSERNAME",
|
||||||
"malId": 42069,
|
"malId": 42069,
|
||||||
|
"discordId": 111111111111111111,
|
||||||
"secret": "1ef539ed34435873fc964c2c20da84f8793ae3731a154cffb41039f2f061cabe97dea18cfffa51c58f3f564f8e7f0cd0a98d7ba3dddb7301c0e7549626ea43af",
|
"secret": "1ef539ed34435873fc964c2c20da84f8793ae3731a154cffb41039f2f061cabe97dea18cfffa51c58f3f564f8e7f0cd0a98d7ba3dddb7301c0e7549626ea43af",
|
||||||
"sauce": "31f3637d8d05ddca7deee89453e3b68a9b74860facd8d5a6768e5ca842571595c8d31e43ce0e996f893578d0bd2b61f3f3820ec03fbb30407e31a2603c887b1"
|
"sauce": "31f3637d8d05ddca7deee89453e3b68a9b74860facd8d5a6768e5ca842571595c8d31e43ce0e996f893578d0bd2b61f3f3820ec03fbb30407e31a2603c887b1"
|
||||||
}
|
}
|
||||||
@@ -43,6 +45,8 @@ _X-HUSO-AUTH_ -> _secret_ des users
|
|||||||
| - | - | - | - | - | - | - |
|
| - | - | - | - | - | - | - |
|
||||||
| GET | /api/season | Aktuelle Season holen | []Anime JSON | | | |
|
| GET | /api/season | Aktuelle Season holen | []Anime JSON | | | |
|
||||||
| GET | /api/nextseason | Nächste Season holen | []Anime JSON | | | |
|
| GET | /api/nextseason | Nächste Season holen | []Anime JSON | | | |
|
||||||
|
| GET | /api/nextnextseason | Übernächste Season holen | []Anime JSON | | | |
|
||||||
|
| GET | /api/lastseason | Letzte Season holen | []Anime JSON | | | |
|
||||||
| GET | /api/anime/{id} | Einzelnen Anime holen | Anime JSON | {id} = MAL Anime id | | |
|
| GET | /api/anime/{id} | Einzelnen Anime holen | Anime JSON | {id} = MAL Anime id | | |
|
||||||
| GET | /api/animesearch | Anime auf MAL suchen | []Anime JSON | Query parameter {q} = Suchtext | | |
|
| GET | /api/animesearch | Anime auf MAL suchen | []Anime JSON | Query parameter {q} = Suchtext | | |
|
||||||
|
|
||||||
@@ -291,3 +295,8 @@ _[]Appointment_ (POST/DELETE)
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
### User data
|
||||||
|
| Method | Route | Description | Response | Parameter | Header | POST-Body |
|
||||||
|
| - | - | - | - | - | - | - |
|
||||||
|
| GET | /api/userdata/{user}/{key} | User data holen | | {user} = MAL username; {key} = Key der data | X-HUSO-AUTH | Plaintext(binary) data |
|
||||||
|
| PUT | /api/userdata/{user}/{key} | User data setzen | Plaintext(binary) data | {user} = MAL username; {key} = Key der data | X-HUSO-AUTH | |
|
||||||
|
|||||||
4
build.sh
4
build.sh
@@ -1,2 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
date=$(date '+%Y-%m-%dT%H:%M:%S')
|
date=$(date '+%Y-%m-%dT%H:%M:%S')
|
||||||
go build -ldflags "-X main.buildTime=$date"
|
commit=$(git log -1 --pretty=format:'%h %B')
|
||||||
|
go build -ldflags "-X 'main.buildTime=$date' -X 'main.buildCommit=$commit'"
|
||||||
|
|||||||
23
go.mod
23
go.mod
@@ -1,25 +1,30 @@
|
|||||||
module github.com/ultrasn0w/huso
|
module github.com/ultrasn0w/huso
|
||||||
|
|
||||||
go 1.18
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/allegro/bigcache/v3 v3.0.2
|
github.com/allegro/bigcache/v3 v3.0.2
|
||||||
github.com/fasthttp/router v1.4.9
|
github.com/bwmarrin/discordgo v0.26.0
|
||||||
github.com/gookit/color v1.5.0
|
github.com/fasthttp/router v1.4.11
|
||||||
github.com/valyala/fasthttp v1.37.0
|
github.com/go-sql-driver/mysql v1.6.0
|
||||||
|
github.com/gookit/color v1.5.1
|
||||||
|
github.com/klauspost/compress v1.15.9
|
||||||
|
github.com/valyala/fasthttp v1.39.0
|
||||||
github.com/valyala/quicktemplate v1.7.0
|
github.com/valyala/quicktemplate v1.7.0
|
||||||
github.com/xujiajun/nutsdb v0.8.0
|
github.com/xujiajun/nutsdb v0.10.0
|
||||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306
|
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||||
github.com/bwmarrin/snowflake v0.3.0 // indirect
|
github.com/bwmarrin/snowflake v0.3.0 // indirect
|
||||||
github.com/klauspost/compress v1.15.5 // indirect
|
github.com/gorilla/websocket v1.5.0 // indirect
|
||||||
github.com/savsgio/gotils v0.0.0-20220401102855-e56b59f40436 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||||
github.com/xujiajun/mmap-go v1.0.1 // indirect
|
github.com/xujiajun/mmap-go v1.0.1 // indirect
|
||||||
github.com/xujiajun/utils v0.0.0-20190123093513-8bf096c4f53b // indirect
|
github.com/xujiajun/utils v0.0.0-20190123093513-8bf096c4f53b // indirect
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
55
go.sum
55
go.sum
@@ -4,35 +4,45 @@ github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu
|
|||||||
github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
|
github.com/bwmarrin/discordgo v0.26.0 h1:/AdFmxHXSHInYAZ7K0O3VEIXlVjGpztk/nuCr9o+JCs=
|
||||||
|
github.com/bwmarrin/discordgo v0.26.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
||||||
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
|
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
|
||||||
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
|
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
|
||||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/fasthttp/router v1.4.9 h1:8s1HEqP+GvsC2B8vPdLAPHJegs4s28z7UsraPuHM1K8=
|
github.com/fasthttp/router v1.4.11 h1:99BvgVxeS2oOZBHnKr/okpdPq1jkn8WvYA2trh/71LY=
|
||||||
github.com/fasthttp/router v1.4.9/go.mod h1:oWPrQCi9QOrzxKC+rZuliS1+JhYj2bpR01J6T8vUDUQ=
|
github.com/fasthttp/router v1.4.11/go.mod h1:luEEYkGBSAmYyPaMeIUGNgqY+FdHHYDOK9Kivaw7aNo=
|
||||||
|
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||||
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw=
|
github.com/gookit/color v1.5.1 h1:Vjg2VEcdHpwq+oY63s/ksHrgJYCTo0bwWvmmYWdE9fQ=
|
||||||
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
|
github.com/gookit/color v1.5.1/go.mod h1:wZFzea4X8qN6vHOSP2apMb4/+w/orMznEzYsIHPaqKM=
|
||||||
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||||
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||||
github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
github.com/klauspost/compress v1.15.5 h1:qyCLMz2JCrKADihKOh9FxnW3houKeNsp2h5OEz0QSEA=
|
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
|
||||||
github.com/klauspost/compress v1.15.5/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/savsgio/gotils v0.0.0-20220401102855-e56b59f40436 h1:sfTahD3f2BSjx9U3R4K09PkNuZZWthT7g6vzTIXNWkM=
|
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d h1:Q+gqLBOPkFGHyCJxXMRqtUgUbTjI8/Ze8vu8GGyNFwo=
|
||||||
github.com/savsgio/gotils v0.0.0-20220401102855-e56b59f40436/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4=
|
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
||||||
|
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
|
github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
|
||||||
github.com/valyala/fasthttp v1.36.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
|
github.com/valyala/fasthttp v1.38.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
|
||||||
github.com/valyala/fasthttp v1.37.0 h1:7WHCyI7EAkQMVmrfBhWTCOaeROb1aCBiTopx63LkMbE=
|
github.com/valyala/fasthttp v1.39.0 h1:lW8mGeM7yydOqZKmwyMTaz/PH/A+CLgtmmcjv+OORfU=
|
||||||
github.com/valyala/fasthttp v1.37.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
|
github.com/valyala/fasthttp v1.39.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
|
||||||
github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM=
|
github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM=
|
||||||
github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8=
|
github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8=
|
||||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||||
@@ -41,12 +51,15 @@ github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1z
|
|||||||
github.com/xujiajun/gorouter v1.2.0/go.mod h1:yJrIta+bTNpBM/2UT8hLOaEAFckO+m/qmR3luMIQygM=
|
github.com/xujiajun/gorouter v1.2.0/go.mod h1:yJrIta+bTNpBM/2UT8hLOaEAFckO+m/qmR3luMIQygM=
|
||||||
github.com/xujiajun/mmap-go v1.0.1 h1:7Se7ss1fLPPRW+ePgqGpCkfGIZzJV6JPq9Wq9iv/WHc=
|
github.com/xujiajun/mmap-go v1.0.1 h1:7Se7ss1fLPPRW+ePgqGpCkfGIZzJV6JPq9Wq9iv/WHc=
|
||||||
github.com/xujiajun/mmap-go v1.0.1/go.mod h1:CNN6Sw4SL69Sui00p0zEzcZKbt+5HtEnYUsc6BKKRMg=
|
github.com/xujiajun/mmap-go v1.0.1/go.mod h1:CNN6Sw4SL69Sui00p0zEzcZKbt+5HtEnYUsc6BKKRMg=
|
||||||
github.com/xujiajun/nutsdb v0.8.0 h1:BkXjifwlF3akHVoTQ8B3gdF183oq4QI0JQywazEZXkM=
|
github.com/xujiajun/nutsdb v0.10.0 h1:kSxd7MyZiAVQM2I79FK74WneGI+uaHsUdak8dbjzKJc=
|
||||||
github.com/xujiajun/nutsdb v0.8.0/go.mod h1:KOdR/RLPELQ6611VTMsSOUBSO2s7kXPINOiA/+1dlgc=
|
github.com/xujiajun/nutsdb v0.10.0/go.mod h1:8ZdTTF0cEQO+wN940htfHYKswFql2iB6Osckx+GmOoU=
|
||||||
github.com/xujiajun/utils v0.0.0-20190123093513-8bf096c4f53b h1:jKG9OiL4T4xQN3IUrhUpc1tG+HfDXppkgVcrAiiaI/0=
|
github.com/xujiajun/utils v0.0.0-20190123093513-8bf096c4f53b h1:jKG9OiL4T4xQN3IUrhUpc1tG+HfDXppkgVcrAiiaI/0=
|
||||||
github.com/xujiajun/utils v0.0.0-20190123093513-8bf096c4f53b/go.mod h1:AZd87GYJlUzl82Yab2kTjx1EyXSQCAfZDhpTo1SQC4k=
|
github.com/xujiajun/utils v0.0.0-20190123093513-8bf096c4f53b/go.mod h1:AZd87GYJlUzl82Yab2kTjx1EyXSQCAfZDhpTo1SQC4k=
|
||||||
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503 h1:vJ2V3lFLg+bBhgroYuRfyN583UzVveQmIXjc8T/y3to=
|
||||||
|
golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
@@ -59,16 +72,18 @@ golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
golang.org/x/sys v0.0.0-20220405210540-1e041c57c461/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-20220823224334-20c2bfdbfe24 h1:TyKJRhyo17yWxOMCTHKWrc5rddHORMlnZ/j57umaUd8=
|
||||||
|
golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24/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-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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
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.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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
|
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
|
||||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
78
huso.go
78
huso.go
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
@@ -11,15 +12,16 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/allegro/bigcache/v3"
|
"github.com/allegro/bigcache/v3"
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/gookit/color"
|
"github.com/gookit/color"
|
||||||
"github.com/xujiajun/nutsdb"
|
"github.com/xujiajun/nutsdb"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
husoVersion = "1.2"
|
husoVersion = "1.7.1"
|
||||||
registerSecret = "綾波レイ"
|
registerSecret = "綾波レイ"
|
||||||
seasonApiJikan = "seasons/now"
|
|
||||||
seasonStrJikan = "seasons/"
|
seasonStrJikan = "seasons/"
|
||||||
userApiJikan = "users/"
|
userApiJikan = "users/"
|
||||||
userApiMal = "users/"
|
userApiMal = "users/"
|
||||||
@@ -35,6 +37,7 @@ const (
|
|||||||
bucketMedia = "media"
|
bucketMedia = "media"
|
||||||
bucketAppoint = "appoint"
|
bucketAppoint = "appoint"
|
||||||
bucketChat = "chat"
|
bucketChat = "chat"
|
||||||
|
bucketStash = "stash"
|
||||||
AppointSplit = "§"
|
AppointSplit = "§"
|
||||||
chatLength = 10101
|
chatLength = 10101
|
||||||
)
|
)
|
||||||
@@ -45,15 +48,26 @@ var (
|
|||||||
jikanApiBaseUri = flag.String("jikanApiBaseUri", "https://api.jikan.moe/v4/", "Jikan API base URL")
|
jikanApiBaseUri = flag.String("jikanApiBaseUri", "https://api.jikan.moe/v4/", "Jikan API base URL")
|
||||||
malApiId = flag.String("malApiId", "cc17dcf40581b9dfc8a5a12dba458153", "MyAnimeList API Client ID")
|
malApiId = flag.String("malApiId", "cc17dcf40581b9dfc8a5a12dba458153", "MyAnimeList API Client ID")
|
||||||
localServer = flag.Bool("localServer", false, "Set varius headers for running locally")
|
localServer = flag.Bool("localServer", false, "Set varius headers for running locally")
|
||||||
|
mmDbServer = flag.String("mmDbServer", "hanami.family:3306", "MovieManager db server")
|
||||||
|
mmDbUser = flag.String("mmDbUser", "yui", "MovieManager db user")
|
||||||
|
discordToken = flag.String("discordToken", "OTk4MTk3MTMzNjE2MzUzMzUw.GKPdLt.zaMvvlikffjBxJO-Qx69A5nQNQxtA-FmkH2yTA", "Discord bot auth token")
|
||||||
|
discordChannel = flag.String("discordChannel", "998277590609559632", "Discord bot channel id")
|
||||||
|
husoWebAnimeUri = flag.String("husoWebAnimeUri", "https://anime.hanami.family/anime/", "HusoWeb Anime base URL")
|
||||||
|
husoWebUserUri = flag.String("husoWebUserUri", "https://anime.hanami.family/user/", "HusoWeb User base URL")
|
||||||
animeCache *bigcache.BigCache
|
animeCache *bigcache.BigCache
|
||||||
seasoncache *bigcache.BigCache
|
seasoncache *bigcache.BigCache
|
||||||
userCache *bigcache.BigCache
|
userCache *bigcache.BigCache
|
||||||
searchCache *bigcache.BigCache
|
searchCache *bigcache.BigCache
|
||||||
animeListCache *bigcache.BigCache
|
animeListCache *bigcache.BigCache
|
||||||
|
mmCache *bigcache.BigCache
|
||||||
db *nutsdb.DB
|
db *nutsdb.DB
|
||||||
|
mmDb *sql.DB
|
||||||
|
discc *discordgo.Session
|
||||||
jikanLimiter *rate.Limiter
|
jikanLimiter *rate.Limiter
|
||||||
logOut *RingBuf
|
logOut *RingBuf
|
||||||
buildTime string
|
buildTime string
|
||||||
|
buildCommit string
|
||||||
|
lastAnnounce *SomewhatThreadSafeTime
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -63,12 +77,14 @@ func main() {
|
|||||||
sc := make(chan os.Signal, 1)
|
sc := make(chan os.Signal, 1)
|
||||||
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
|
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
|
||||||
|
|
||||||
logOut = NewRingBuf(10101)
|
logOut = NewRingBuf(101010)
|
||||||
|
|
||||||
color.Notice.Printf("huso %s built on %s with %s\n", husoVersion, buildTime, runtime.Version())
|
color.Notice.Printf("huso %s built on %s with %s\n", husoVersion, buildTime, runtime.Version())
|
||||||
logOut.WriteLine(fmt.Sprintf("🎉 huso %s built on %s with %s\n", husoVersion, buildTime, runtime.Version()))
|
color.Notice.Printf("Last git commit: %s\n", buildCommit)
|
||||||
|
logOut.WriteLine(fmt.Sprintf("🎉 huso %s built on %s with %s", husoVersion, buildTime, runtime.Version()))
|
||||||
|
logOut.WriteLine(fmt.Sprintf("🪄 Last git commit: %s", buildCommit))
|
||||||
|
|
||||||
jikanLimiter = rate.NewLimiter(rate.Every(time.Second), 1)
|
jikanLimiter = rate.NewLimiter(rate.Every(time.Second+(time.Millisecond*420)), 1)
|
||||||
|
|
||||||
// cache init
|
// cache init
|
||||||
var err error
|
var err error
|
||||||
@@ -92,11 +108,16 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer searchCache.Close()
|
defer searchCache.Close()
|
||||||
animeListCache, err = bigcache.NewBigCache(bigcache.DefaultConfig(42 * time.Minute))
|
animeListCache, err = bigcache.NewBigCache(bigcache.DefaultConfig(15 * time.Minute))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer animeListCache.Close()
|
defer animeListCache.Close()
|
||||||
|
mmCache, err = bigcache.NewBigCache(bigcache.DefaultConfig(time.Minute))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer mmCache.Close()
|
||||||
|
|
||||||
nutsOpt := nutsdb.DefaultOptions
|
nutsOpt := nutsdb.DefaultOptions
|
||||||
nutsOpt.Dir = "nuts"
|
nutsOpt.Dir = "nuts"
|
||||||
@@ -106,7 +127,52 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
|
lastAnnounce = &SomewhatThreadSafeTime{
|
||||||
|
stamp: time.Now().Add(-1 * time.Hour),
|
||||||
|
}
|
||||||
|
|
||||||
|
color.Infoln("NutsDB connected")
|
||||||
|
logOut.WriteLine("🗃️ NutsDB connected")
|
||||||
|
|
||||||
|
conns, err := GetMmConnString()
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
} else {
|
||||||
|
mmDb, err = sql.Open("mysql", conns)
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
} else {
|
||||||
|
mmDb.SetConnMaxLifetime(time.Minute * 3)
|
||||||
|
mmDb.SetMaxOpenConns(10)
|
||||||
|
mmDb.SetMaxIdleConns(10)
|
||||||
|
defer mmDb.Close()
|
||||||
|
|
||||||
|
err = mmDb.Ping()
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
} else {
|
||||||
|
color.Infoln("MovieManager DB connected")
|
||||||
|
logOut.WriteLine("🗃️ MovieManager DB connected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
discc, err = discordgo.New("Bot " + *discordToken)
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
} else {
|
||||||
|
err = discc.Open()
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
} else {
|
||||||
|
defer discc.Close()
|
||||||
|
color.Infoln("Discord huso online")
|
||||||
|
logOut.WriteLine("📯 Discord huso online")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Arbeit()
|
Arbeit()
|
||||||
|
BissleArbeit()
|
||||||
LangeArbeit()
|
LangeArbeit()
|
||||||
|
|
||||||
go Arbeiten()
|
go Arbeiten()
|
||||||
|
|||||||
40
klotz.go
40
klotz.go
@@ -1,6 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type AnimeUser struct {
|
type AnimeUser struct {
|
||||||
Anime int64 `json:"anime"`
|
Anime int64 `json:"anime"`
|
||||||
@@ -58,6 +61,7 @@ type Appointment struct {
|
|||||||
Anime int64 `json:"anime"`
|
Anime int64 `json:"anime"`
|
||||||
Time time.Time `json:"date"`
|
Time time.Time `json:"date"`
|
||||||
Users []string `json:"users"`
|
Users []string `json:"users"`
|
||||||
|
Announced bool `json:"announced"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WatchUser struct {
|
type WatchUser struct {
|
||||||
@@ -67,12 +71,6 @@ type WatchUser struct {
|
|||||||
Updated time.Time `json:"updated"`
|
Updated time.Time `json:"updated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserData struct {
|
|
||||||
Username string `json:"username"`
|
|
||||||
MalID int64 `json:"malId"`
|
|
||||||
Secret string `json:"secret"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
MalID int64 `json:"id"`
|
MalID int64 `json:"id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
@@ -85,9 +83,17 @@ type User struct {
|
|||||||
Joined time.Time `json:"joined"`
|
Joined time.Time `json:"joined"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserData struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
MalID int64 `json:"malId"`
|
||||||
|
DiscordID int64 `json:"discordId"`
|
||||||
|
Secret string `json:"secret"`
|
||||||
|
}
|
||||||
|
|
||||||
type RegisterData struct {
|
type RegisterData struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
MalID int64 `json:"malId"`
|
MalID int64 `json:"malId"`
|
||||||
|
DiscordID int64 `json:"discordId"`
|
||||||
Secret string `json:"secret"`
|
Secret string `json:"secret"`
|
||||||
Sauce string `json:"sauce"`
|
Sauce string `json:"sauce"`
|
||||||
}
|
}
|
||||||
@@ -310,3 +316,23 @@ type SeasonJikan struct {
|
|||||||
} `json:"pagination"`
|
} `json:"pagination"`
|
||||||
Data []SeasonAnimeJikan `json:"data"`
|
Data []SeasonAnimeJikan `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MmOracle struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Anime int64 `json:"anime"`
|
||||||
|
AvgScore int `json:"avgScore"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MovieChart struct {
|
||||||
|
MmId int `json:"mmId"`
|
||||||
|
Anime int64 `json:"anime"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
AvgScore float64 `json:"avgScore"`
|
||||||
|
UserCount int `json:"userCount"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SomewhatThreadSafeTime struct {
|
||||||
|
sync.Mutex
|
||||||
|
stamp time.Time
|
||||||
|
}
|
||||||
|
|||||||
119
knecht.go
119
knecht.go
@@ -8,6 +8,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/gookit/color"
|
"github.com/gookit/color"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
@@ -18,12 +19,21 @@ func SearchAnimeData(query string) ([]Anime, []byte, error) {
|
|||||||
data, err := searchCache.Get(query)
|
data, err := searchCache.Get(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = nil
|
err = nil
|
||||||
|
animes = make([]Anime, 0)
|
||||||
|
parseId, err := strconv.ParseInt(query, 10, 64)
|
||||||
|
if err == nil && parseId > 0 {
|
||||||
|
anime, err := SearchAnime(parseId)
|
||||||
|
if err == nil {
|
||||||
|
animes = append(animes, *anime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = nil
|
||||||
|
if utf8.RuneCountInString(query) > 2 {
|
||||||
dataMal, err := GetDataMal(searchApiMal + query + "&fields=id,title,main_picture,alternative_titles,start_date,end_date,synopsis,mean,rank,popularity,num_list_users,num_scoring_users,nsfw,media_type,status,genres,my_list_status,num_episodes,start_season,broadcast,source,average_episode_duration,rating,studios&limit=100")
|
dataMal, err := GetDataMal(searchApiMal + query + "&fields=id,title,main_picture,alternative_titles,start_date,end_date,synopsis,mean,rank,popularity,num_list_users,num_scoring_users,nsfw,media_type,status,genres,my_list_status,num_episodes,start_season,broadcast,source,average_episode_duration,rating,studios&limit=100")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
var animeList AnimeListMal
|
var animeList AnimeListMal
|
||||||
animes = make([]Anime, 0)
|
|
||||||
err = json.Unmarshal(dataMal, &animeList)
|
err = json.Unmarshal(dataMal, &animeList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -32,6 +42,7 @@ func SearchAnimeData(query string) ([]Anime, []byte, error) {
|
|||||||
for _, a := range animeList.Data {
|
for _, a := range animeList.Data {
|
||||||
animes = append(animes, MalConvert(&a.Node))
|
animes = append(animes, MalConvert(&a.Node))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
data, err = json.Marshal(animes)
|
data, err = json.Marshal(animes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return animes, data, err
|
return animes, data, err
|
||||||
@@ -75,7 +86,9 @@ func GetUserAnimeListData(username, status string) (*AnimeListMal, []byte, error
|
|||||||
var list AnimeListMal
|
var list AnimeListMal
|
||||||
data, err := animeListCache.Get(username + status)
|
data, err := animeListCache.Get(username + status)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
data, err = GetDataMal(userApiMal + username + "/animelist?limit=1000&status=" + status + "&fields=list_status")
|
color.Infoln(username + "'s " + status + " abfragen...")
|
||||||
|
//logOut.WriteLine("📄 " + username + "'s " + status + " abfragen...")
|
||||||
|
data, err = GetDataMal(userApiMal + username + "/animelist?limit=1000&status=" + status + "&fields=list_status&nsfw=true")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -85,11 +98,25 @@ func GetUserAnimeListData(username, status string) (*AnimeListMal, []byte, error
|
|||||||
return &list, data, err
|
return &list, data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserData(username string) (*User, []byte, error) {
|
func GetUser(username string) (*User, []byte, error) {
|
||||||
var user User
|
var user User
|
||||||
data, err := userCache.Get(username)
|
data, err := userCache.Get(username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = nil
|
err = nil
|
||||||
|
userp, data, err := GetUserData(username)
|
||||||
|
if err != nil {
|
||||||
|
return userp, data, err
|
||||||
|
}
|
||||||
|
userCache.Set(username, data)
|
||||||
|
return userp, data, err
|
||||||
|
} else {
|
||||||
|
err = json.Unmarshal(data, &user)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &user, data, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUserData(username string) (*User, []byte, error) {
|
||||||
dataJikan, err := GetDataJikan(userApiJikan + username)
|
dataJikan, err := GetDataJikan(userApiJikan + username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -120,58 +147,14 @@ func GetUserData(username string) (*User, []byte, error) {
|
|||||||
return nil, nil, fmt.Errorf("user returned empty object: %s", username)
|
return nil, nil, fmt.Errorf("user returned empty object: %s", username)
|
||||||
}
|
}
|
||||||
// convert to user
|
// convert to user
|
||||||
user = UserConvert(&userJikan)
|
user := UserConvert(&userJikan)
|
||||||
data, err = json.Marshal(&user)
|
data, err := json.Marshal(&user)
|
||||||
if err != nil {
|
|
||||||
return &user, data, err
|
|
||||||
}
|
|
||||||
userCache.Set(username, data)
|
|
||||||
} else {
|
|
||||||
err = json.Unmarshal(data, &user)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &user, data, err
|
return &user, data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSeasonDataAll() ([]Anime, []byte, error) {
|
func GetSeasonDataAll(season string) ([]Anime, []byte, error) {
|
||||||
seasonStr := GetCurrentSeasonString()
|
color.Infoln("Season " + season + " abfragen...")
|
||||||
color.Infoln("Aktuelle Season (" + seasonStr + ") abfragen...")
|
logOut.WriteLine("📺 Season " + season + " abfragen...")
|
||||||
logOut.WriteLine("📺 Aktuelle Season (" + seasonStr + ") abfragen...")
|
|
||||||
data, _, err := GetSeasonData(seasonApiJikan, 1)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
color.Infof("%d Anime auf %d Seiten\n", data.Pagination.Items.Total, data.Pagination.LastVisiblePage)
|
|
||||||
logOut.WriteLine(fmt.Sprintf("📺 %d Anime auf %d Seiten", data.Pagination.Items.Total, data.Pagination.LastVisiblePage))
|
|
||||||
animes := make([]Anime, 0)
|
|
||||||
// convert to anime
|
|
||||||
for _, a := range data.Data {
|
|
||||||
animes = append(animes, JikanConvert(&a))
|
|
||||||
}
|
|
||||||
for i := 2; data.Pagination.HasNextPage; i++ {
|
|
||||||
color.Infof("Seite %d abfragen...\n", i)
|
|
||||||
logOut.WriteLine(fmt.Sprintf("📺 Seite %d abfragen...", i))
|
|
||||||
newData, _, err := GetSeasonData(seasonApiJikan, i)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
data.Pagination.CurrentPage = newData.Pagination.CurrentPage
|
|
||||||
data.Pagination.HasNextPage = newData.Pagination.HasNextPage
|
|
||||||
data.Pagination.Items.Count += newData.Pagination.Items.Count
|
|
||||||
// convert to anime
|
|
||||||
for _, a := range newData.Data {
|
|
||||||
animes = append(animes, JikanConvert(&a))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
color.Infof("%d Anime bekommen\n", len(animes))
|
|
||||||
logOut.WriteLine(fmt.Sprintf("📺 %d Anime bekommen", len(animes)))
|
|
||||||
bytes, err := json.Marshal(animes)
|
|
||||||
return animes, bytes, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetNextSeasonDataAll(season string) ([]Anime, []byte, error) {
|
|
||||||
color.Infoln("Nächste Season (" + season + ") abfragen...")
|
|
||||||
logOut.WriteLine("📺 Nächste Season (" + season + ") abfragen...")
|
|
||||||
data, _, err := GetSeasonData(seasonStrJikan+season, 1)
|
data, _, err := GetSeasonData(seasonStrJikan+season, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -292,3 +275,35 @@ func GetNextSeasonString() string {
|
|||||||
return fmt.Sprintf("%04d", now.Year())
|
return fmt.Sprintf("%04d", now.Year())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetNextNextSeasonString() string {
|
||||||
|
var now = time.Now()
|
||||||
|
switch now.Month() {
|
||||||
|
case time.January, time.February, time.March:
|
||||||
|
return fmt.Sprintf("%04d/summer", now.Year())
|
||||||
|
case time.April, time.May, time.June:
|
||||||
|
return fmt.Sprintf("%04d/fall", now.Year())
|
||||||
|
case time.July, time.August, time.September:
|
||||||
|
return fmt.Sprintf("%04d/winter", now.Year()+1)
|
||||||
|
case time.October, time.November, time.December:
|
||||||
|
return fmt.Sprintf("%04d/spring", now.Year()+1)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("%04d", now.Year())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLastSeasonString() string {
|
||||||
|
var now = time.Now()
|
||||||
|
switch now.Month() {
|
||||||
|
case time.January, time.February, time.March:
|
||||||
|
return fmt.Sprintf("%04d/fall", now.Year()-1)
|
||||||
|
case time.April, time.May, time.June:
|
||||||
|
return fmt.Sprintf("%04d/winter", now.Year())
|
||||||
|
case time.July, time.August, time.September:
|
||||||
|
return fmt.Sprintf("%04d/spring", now.Year())
|
||||||
|
case time.October, time.November, time.December:
|
||||||
|
return fmt.Sprintf("%04d/summer", now.Year())
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("%04d", now.Year())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
114
labersack.go
Normal file
114
labersack.go
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"github.com/gookit/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SendAppointBroadcast(creator string, app *Appointment) {
|
||||||
|
if app != nil && discc != nil {
|
||||||
|
watchData, err := GetAnimeWatchFromDb(app.Anime)
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
anime, err := SearchAnime(app.Anime)
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var msgStart strings.Builder
|
||||||
|
for _, u := range watchData.Users {
|
||||||
|
uData, err := ReadUser(u.Username)
|
||||||
|
if err != nil || uData.DiscordID == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
msgStart.WriteString(fmt.Sprintf("<@%d>", uData.DiscordID))
|
||||||
|
}
|
||||||
|
|
||||||
|
msgs := fmt.Sprintf("🗓️ New appointment for [%s](%s%d) at\n<t:%d:F>\n<t:%d:R>", anime.Title, *husoWebAnimeUri, app.Anime, app.Time.Unix(), app.Time.Unix())
|
||||||
|
msge := discordgo.MessageEmbed{
|
||||||
|
Description: msgs,
|
||||||
|
URL: fmt.Sprintf("%s%d", *husoWebAnimeUri, app.Anime),
|
||||||
|
Thumbnail: &discordgo.MessageEmbedThumbnail{URL: anime.ImageLargeURL},
|
||||||
|
Color: 7187428,
|
||||||
|
Footer: &discordgo.MessageEmbedFooter{
|
||||||
|
Text: "huso " + husoVersion,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
user, _, err := GetUser(creator)
|
||||||
|
if err == nil {
|
||||||
|
msge.Author = &discordgo.MessageEmbedAuthor{
|
||||||
|
Name: user.Username,
|
||||||
|
IconURL: user.ImageURL,
|
||||||
|
URL: fmt.Sprintf("%s%s", *husoWebUserUri, creator),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msgc := discordgo.MessageSend{
|
||||||
|
Content: msgStart.String(),
|
||||||
|
Embeds: []*discordgo.MessageEmbed{&msge},
|
||||||
|
}
|
||||||
|
_, err = discc.ChannelMessageSendComplex(*discordChannel, &msgc)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AnnounceBomb(animeId, meetingUnix int64, timer time.Duration) {
|
||||||
|
time.Sleep(timer)
|
||||||
|
AnnounceAppointmentSoon(animeId, meetingUnix)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AnnounceAppointmentSoon(animeId, meetingUnix int64) {
|
||||||
|
if animeId != 0 && discc != nil {
|
||||||
|
watchData, err := GetAnimeWatchFromDb(animeId)
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
anime, err := SearchAnime(animeId)
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var msgStart strings.Builder
|
||||||
|
for _, u := range watchData.Users {
|
||||||
|
uData, err := ReadUser(u.Username)
|
||||||
|
if err != nil || uData.DiscordID == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
msgStart.WriteString(fmt.Sprintf("<@%d>", uData.DiscordID))
|
||||||
|
}
|
||||||
|
|
||||||
|
msgs := fmt.Sprintf("⏰ Appointment starting <t:%d:R>!\n[%s](%s%d) at\n<t:%d:F>", meetingUnix, anime.Title, *husoWebAnimeUri, animeId, meetingUnix)
|
||||||
|
msge := discordgo.MessageEmbed{
|
||||||
|
Description: msgs,
|
||||||
|
URL: fmt.Sprintf("%s%d", *husoWebAnimeUri, animeId),
|
||||||
|
Thumbnail: &discordgo.MessageEmbedThumbnail{URL: anime.ImageLargeURL},
|
||||||
|
Color: 7187428,
|
||||||
|
Footer: &discordgo.MessageEmbedFooter{
|
||||||
|
Text: "huso " + husoVersion,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
msgc := discordgo.MessageSend{
|
||||||
|
Content: msgStart.String(),
|
||||||
|
Embeds: []*discordgo.MessageEmbed{&msge},
|
||||||
|
}
|
||||||
|
_, err = discc.ChannelMessageSendComplex(*discordChannel, &msgc)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
nuss.go
7
nuss.go
@@ -79,14 +79,16 @@ func AddUserToAnime(username string, userId, animeId int64, progress int, update
|
|||||||
return &anime, err
|
return &anime, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddUserToAppointment(username string, animeId int64, meeting time.Time) (*Appointment, error) {
|
func AddUserToAppointment(username string, animeId int64, meeting time.Time) (*Appointment, bool, error) {
|
||||||
var appoint Appointment
|
var appoint Appointment
|
||||||
|
fresh := false
|
||||||
err := db.Update(
|
err := db.Update(
|
||||||
func(tx *nutsdb.Tx) error {
|
func(tx *nutsdb.Tx) error {
|
||||||
keyBytes := Int64AndDateToBytes(animeId, meeting)
|
keyBytes := Int64AndDateToBytes(animeId, meeting)
|
||||||
e, err := tx.Get(bucketAppoint, keyBytes)
|
e, err := tx.Get(bucketAppoint, keyBytes)
|
||||||
var users []string
|
var users []string
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fresh = true
|
||||||
users = make([]string, 0)
|
users = make([]string, 0)
|
||||||
} else {
|
} else {
|
||||||
// parse user list
|
// parse user list
|
||||||
@@ -121,7 +123,7 @@ func AddUserToAppointment(username string, animeId int64, meeting time.Time) (*A
|
|||||||
}
|
}
|
||||||
return tx.Put(bucketAppoint, keyBytes, newData, nutsdb.Persistent)
|
return tx.Put(bucketAppoint, keyBytes, newData, nutsdb.Persistent)
|
||||||
})
|
})
|
||||||
return &appoint, err
|
return &appoint, fresh, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteUserFromAnime(username string, userId, animeId int64) (*AnimeUser, error) {
|
func DeleteUserFromAnime(username string, userId, animeId int64) (*AnimeUser, error) {
|
||||||
@@ -433,6 +435,7 @@ func ReadAppointments() ([]Appointment, error) {
|
|||||||
Anime: animeId,
|
Anime: animeId,
|
||||||
Time: date,
|
Time: date,
|
||||||
Users: appointmentUsers,
|
Users: appointmentUsers,
|
||||||
|
Announced: false,
|
||||||
}
|
}
|
||||||
appoints = append(appoints, appointment)
|
appoints = append(appoints, appointment)
|
||||||
}
|
}
|
||||||
|
|||||||
305
ober.go
305
ober.go
@@ -4,20 +4,31 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fasthttp/router"
|
"github.com/fasthttp/router"
|
||||||
|
"github.com/gookit/color"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
"github.com/xujiajun/nutsdb"
|
"github.com/xujiajun/nutsdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
xHusoAuth = "X-HUSO-AUTH"
|
||||||
|
htmlContentType = "text/html; charset=utf-8"
|
||||||
|
jsonContentType = "application/json; charset=utf-8"
|
||||||
|
textContentType = "text/plain; charset=utf-8"
|
||||||
|
)
|
||||||
|
|
||||||
func RunWebserv() {
|
func RunWebserv() {
|
||||||
r := router.New()
|
r := router.New()
|
||||||
r.GET("/", Headers(Start))
|
r.GET("/", Headers(Start))
|
||||||
r.GET("/api/season", Headers(Season))
|
r.GET("/api/season", Headers(Season))
|
||||||
r.GET("/api/nextseason", Headers(SeasonNext))
|
r.GET("/api/nextseason", Headers(SeasonNext))
|
||||||
|
r.GET("/api/nextnextseason", Headers(SeasonNextNext))
|
||||||
|
r.GET("/api/lastseason", Headers(SeasonLast))
|
||||||
r.GET("/api/auth/{user}", Headers(AuthTest))
|
r.GET("/api/auth/{user}", Headers(AuthTest))
|
||||||
r.GET("/api/anime/{id}", Headers(AnimeGet))
|
r.GET("/api/anime/{id}", Headers(AnimeGet))
|
||||||
r.GET("/api/animesearch", Headers(AnimeSearchGet))
|
r.GET("/api/animesearch", Headers(AnimeSearchGet))
|
||||||
@@ -25,12 +36,15 @@ func RunWebserv() {
|
|||||||
r.GET("/api/chat/{id}", Headers(ChatGet))
|
r.GET("/api/chat/{id}", Headers(ChatGet))
|
||||||
r.GET("/api/log", Headers(LogGet))
|
r.GET("/api/log", Headers(LogGet))
|
||||||
r.GET("/api/user/{user?}", Headers(UserGet))
|
r.GET("/api/user/{user?}", Headers(UserGet))
|
||||||
|
r.GET("/api/userdata/{user}/{data}", Headers(UserStashGet))
|
||||||
r.GET("/api/watch/{user?}", Headers(WatchGet))
|
r.GET("/api/watch/{user?}", Headers(WatchGet))
|
||||||
r.GET("/api/watchext/{user?}", Headers(WatchExtendedGet))
|
r.GET("/api/watchext/{user?}", Headers(WatchExtendedGet))
|
||||||
r.POST("/api/appointment/{user}", Headers(AppointmentPost))
|
r.POST("/api/appointment/{user}", Headers(AppointmentPost))
|
||||||
r.POST("/api/chat/{id}/{user}", Headers(ChatPost))
|
r.POST("/api/chat/{id}/{user}", Headers(ChatPost))
|
||||||
r.POST("/api/register", Headers(Register))
|
r.POST("/api/register", Headers(Register))
|
||||||
r.POST("/api/watch/{user}", Headers(WatchPost))
|
r.POST("/api/watch/{user}", Headers(WatchPost))
|
||||||
|
r.PATCH("/api/register", Headers(RegisterUpdate))
|
||||||
|
r.PUT("/api/userdata/{user}/{data}", Headers(UserStashPut))
|
||||||
r.DELETE("/api/appointment/{user}", Headers(AppointmentDelete))
|
r.DELETE("/api/appointment/{user}", Headers(AppointmentDelete))
|
||||||
r.DELETE("/api/register", Headers(UnRegister))
|
r.DELETE("/api/register", Headers(UnRegister))
|
||||||
r.DELETE("/api/watch/{user}", Headers(WatchDelete))
|
r.DELETE("/api/watch/{user}", Headers(WatchDelete))
|
||||||
@@ -38,20 +52,30 @@ func RunWebserv() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Start(ctx *fasthttp.RequestCtx) {
|
func Start(ctx *fasthttp.RequestCtx) {
|
||||||
season, err := GetSeasonCache(seasonApiJikan)
|
season, err := GetSeasonCache(GetCurrentSeasonString())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteIndex(ctx, season, logOut.String())
|
oracles, err := MmReadOracle()
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
ctx.SetContentType("text/html; charset=utf-8")
|
charts, err := BuildMovieCharts()
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteIndex(ctx, season, oracles, charts, logOut.String())
|
||||||
|
|
||||||
|
ctx.SetContentType(htmlContentType)
|
||||||
ctx.SetStatusCode(fasthttp.StatusOK)
|
ctx.SetStatusCode(fasthttp.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func AuthTest(ctx *fasthttp.RequestCtx) {
|
func AuthTest(ctx *fasthttp.RequestCtx) {
|
||||||
auth := ctx.Request.Header.Peek("X-HUSO-AUTH")
|
auth := ctx.Request.Header.Peek(xHusoAuth)
|
||||||
if ctx.UserValue("user") == nil || auth == nil || string(auth) == "" {
|
if ctx.UserValue("user") == nil || auth == nil || string(auth) == "" {
|
||||||
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@@ -66,20 +90,12 @@ func AuthTest(ctx *fasthttp.RequestCtx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Season(ctx *fasthttp.RequestCtx) {
|
func Season(ctx *fasthttp.RequestCtx) {
|
||||||
data, err := seasoncache.Get(seasonApiJikan)
|
data, err := seasoncache.Get(GetCurrentSeasonString())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
setResponseJson(ctx, data)
|
||||||
err = writeResponseBody(ctx, data)
|
|
||||||
if err != nil {
|
|
||||||
addErrorToCtx(ctx, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.SetContentType("application/json; charset=utf-8")
|
|
||||||
ctx.SetStatusCode(fasthttp.StatusOK)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func SeasonNext(ctx *fasthttp.RequestCtx) {
|
func SeasonNext(ctx *fasthttp.RequestCtx) {
|
||||||
@@ -88,15 +104,25 @@ func SeasonNext(ctx *fasthttp.RequestCtx) {
|
|||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
setResponseJson(ctx, data)
|
||||||
|
}
|
||||||
|
|
||||||
err = writeResponseBody(ctx, data)
|
func SeasonNextNext(ctx *fasthttp.RequestCtx) {
|
||||||
|
data, err := seasoncache.Get(GetNextNextSeasonString())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
setResponseJson(ctx, data)
|
||||||
|
}
|
||||||
|
|
||||||
ctx.SetContentType("application/json; charset=utf-8")
|
func SeasonLast(ctx *fasthttp.RequestCtx) {
|
||||||
ctx.SetStatusCode(fasthttp.StatusOK)
|
data, err := seasoncache.Get(GetLastSeasonString())
|
||||||
|
if err != nil {
|
||||||
|
addErrorToCtx(ctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setResponseJson(ctx, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func AnimeGet(ctx *fasthttp.RequestCtx) {
|
func AnimeGet(ctx *fasthttp.RequestCtx) {
|
||||||
@@ -123,14 +149,7 @@ func AnimeGet(ctx *fasthttp.RequestCtx) {
|
|||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = ctx.Write(bytes)
|
setResponseJson(ctx, bytes)
|
||||||
if err != nil {
|
|
||||||
addErrorToCtx(ctx, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.SetContentType("application/json; charset=utf-8")
|
|
||||||
ctx.SetStatusCode(fasthttp.StatusOK)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func AnimeSearchGet(ctx *fasthttp.RequestCtx) {
|
func AnimeSearchGet(ctx *fasthttp.RequestCtx) {
|
||||||
@@ -145,14 +164,7 @@ func AnimeSearchGet(ctx *fasthttp.RequestCtx) {
|
|||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = ctx.Write(bytes)
|
setResponseJson(ctx, bytes)
|
||||||
if err != nil {
|
|
||||||
addErrorToCtx(ctx, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.SetContentType("application/json; charset=utf-8")
|
|
||||||
ctx.SetStatusCode(fasthttp.StatusOK)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func AppointmentGet(ctx *fasthttp.RequestCtx) {
|
func AppointmentGet(ctx *fasthttp.RequestCtx) {
|
||||||
@@ -172,14 +184,7 @@ func AppointmentGet(ctx *fasthttp.RequestCtx) {
|
|||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = ctx.Write(bytes)
|
setResponseJson(ctx, bytes)
|
||||||
if err != nil {
|
|
||||||
addErrorToCtx(ctx, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.SetContentType("application/json; charset=utf-8")
|
|
||||||
ctx.SetStatusCode(fasthttp.StatusOK)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChatGet(ctx *fasthttp.RequestCtx) {
|
func ChatGet(ctx *fasthttp.RequestCtx) {
|
||||||
@@ -218,7 +223,7 @@ func ChatGet(ctx *fasthttp.RequestCtx) {
|
|||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.SetContentType("text/plain; charset=utf-8")
|
ctx.SetContentType(textContentType)
|
||||||
ctx.SetStatusCode(fasthttp.StatusOK)
|
ctx.SetStatusCode(fasthttp.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +233,7 @@ func LogGet(ctx *fasthttp.RequestCtx) {
|
|||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.SetContentType("text/plain; charset=utf-8")
|
ctx.SetContentType(textContentType)
|
||||||
ctx.SetStatusCode(fasthttp.StatusOK)
|
ctx.SetStatusCode(fasthttp.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +242,7 @@ func UserGet(ctx *fasthttp.RequestCtx) {
|
|||||||
users := make([]User, 0)
|
users := make([]User, 0)
|
||||||
if usrVal != nil {
|
if usrVal != nil {
|
||||||
// get specific user
|
// get specific user
|
||||||
user, _, err := GetUserData(fmt.Sprintf("%s", usrVal))
|
user, _, err := GetUser(fmt.Sprintf("%s", usrVal))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.WriteString(err.Error())
|
ctx.WriteString(err.Error())
|
||||||
ctx.SetStatusCode(fasthttp.StatusNotFound)
|
ctx.SetStatusCode(fasthttp.StatusNotFound)
|
||||||
@@ -255,7 +260,7 @@ func UserGet(ctx *fasthttp.RequestCtx) {
|
|||||||
regUsers = make([]UserData, 0)
|
regUsers = make([]UserData, 0)
|
||||||
}
|
}
|
||||||
for _, u := range regUsers {
|
for _, u := range regUsers {
|
||||||
user, _, err := GetUserData(u.Username)
|
user, _, err := GetUser(u.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
@@ -269,14 +274,11 @@ func UserGet(ctx *fasthttp.RequestCtx) {
|
|||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = ctx.Write(bytes)
|
setResponseJson(ctx, bytes)
|
||||||
if err != nil {
|
|
||||||
addErrorToCtx(ctx, err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.SetContentType("application/json; charset=utf-8")
|
func UserStashGet(ctx *fasthttp.RequestCtx) {
|
||||||
ctx.SetStatusCode(fasthttp.StatusOK)
|
processUserStashReq(ctx, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func WatchGet(ctx *fasthttp.RequestCtx) {
|
func WatchGet(ctx *fasthttp.RequestCtx) {
|
||||||
@@ -291,14 +293,7 @@ func WatchGet(ctx *fasthttp.RequestCtx) {
|
|||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = ctx.Write(bytes)
|
setResponseJson(ctx, bytes)
|
||||||
if err != nil {
|
|
||||||
addErrorToCtx(ctx, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.SetContentType("application/json; charset=utf-8")
|
|
||||||
ctx.SetStatusCode(fasthttp.StatusOK)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func WatchExtendedGet(ctx *fasthttp.RequestCtx) {
|
func WatchExtendedGet(ctx *fasthttp.RequestCtx) {
|
||||||
@@ -334,14 +329,7 @@ func WatchExtendedGet(ctx *fasthttp.RequestCtx) {
|
|||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = ctx.Write(bytes)
|
setResponseJson(ctx, bytes)
|
||||||
if err != nil {
|
|
||||||
addErrorToCtx(ctx, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.SetContentType("application/json; charset=utf-8")
|
|
||||||
ctx.SetStatusCode(fasthttp.StatusOK)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Register(ctx *fasthttp.RequestCtx) {
|
func Register(ctx *fasthttp.RequestCtx) {
|
||||||
@@ -376,7 +364,7 @@ func Register(ctx *fasthttp.RequestCtx) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// check user legit
|
// check user legit
|
||||||
userData, _, err := GetUserData(register.Username)
|
userData, _, err := GetUser(register.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.WriteString(err.Error())
|
ctx.WriteString(err.Error())
|
||||||
ctx.SetStatusCode(fasthttp.StatusExpectationFailed)
|
ctx.SetStatusCode(fasthttp.StatusExpectationFailed)
|
||||||
@@ -387,11 +375,21 @@ func Register(ctx *fasthttp.RequestCtx) {
|
|||||||
ctx.SetStatusCode(fasthttp.StatusExpectationFailed)
|
ctx.SetStatusCode(fasthttp.StatusExpectationFailed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// check user discord id
|
||||||
|
if register.DiscordID != 0 && discc != nil {
|
||||||
|
_, err = discc.User(fmt.Sprint(register.DiscordID != 0))
|
||||||
|
if err != nil {
|
||||||
|
ctx.WriteString("Discord user id is kaputt")
|
||||||
|
ctx.SetStatusCode(fasthttp.StatusExpectationFailed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
// REGISTER
|
// REGISTER
|
||||||
user := UserData{
|
user := UserData{
|
||||||
Username: register.Username,
|
Username: register.Username,
|
||||||
MalID: register.MalID,
|
MalID: register.MalID,
|
||||||
Secret: register.Secret,
|
Secret: register.Secret,
|
||||||
|
DiscordID: register.DiscordID,
|
||||||
}
|
}
|
||||||
err = SaveUser(&user)
|
err = SaveUser(&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -399,9 +397,74 @@ func Register(ctx *fasthttp.RequestCtx) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.SetBody(body)
|
setResponseJson(ctx, body)
|
||||||
ctx.SetContentType("application/json; charset=utf-8")
|
}
|
||||||
ctx.SetStatusCode(fasthttp.StatusOK)
|
|
||||||
|
func RegisterUpdate(ctx *fasthttp.RequestCtx) {
|
||||||
|
auth := ctx.Request.Header.Peek(xHusoAuth)
|
||||||
|
if auth == nil || string(auth) == "" || !strings.Contains(string(ctx.Request.Header.ContentType()), "application/json") {
|
||||||
|
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
body := ctx.PostBody()
|
||||||
|
var regUpdate RegisterData
|
||||||
|
err := json.Unmarshal(body, ®Update)
|
||||||
|
if err != nil {
|
||||||
|
ctx.WriteString(err.Error())
|
||||||
|
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if regUpdate.MalID == 0 || regUpdate.Username == "" || regUpdate.Sauce == "" {
|
||||||
|
ctx.WriteString("Sprich JSON du Hurensohn")
|
||||||
|
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
legit, _ := GheddoAuth(regUpdate.Username, string(auth))
|
||||||
|
if !legit {
|
||||||
|
ctx.SetStatusCode(fasthttp.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
calcSauce := Sauce(regUpdate.MalID, regUpdate.Username)
|
||||||
|
if calcSauce != strings.ToLower(regUpdate.Sauce) {
|
||||||
|
ctx.WriteString("Möge die Sauce mit dir sein")
|
||||||
|
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// check user exists
|
||||||
|
user, err := ReadUser(regUpdate.Username)
|
||||||
|
if err != nil {
|
||||||
|
ctx.WriteString("Dich gibts hier nicht wtf")
|
||||||
|
ctx.SetStatusCode(fasthttp.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if regUpdate.MalID != user.MalID {
|
||||||
|
ctx.WriteString("MAL id ändern is nich")
|
||||||
|
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if regUpdate.Secret != "" {
|
||||||
|
user.Secret = regUpdate.Secret
|
||||||
|
}
|
||||||
|
|
||||||
|
// check user discord id
|
||||||
|
if regUpdate.DiscordID != 0 && discc != nil {
|
||||||
|
_, err = discc.User(fmt.Sprint(regUpdate.DiscordID))
|
||||||
|
if err != nil {
|
||||||
|
ctx.WriteString("Discord user id is kaputt")
|
||||||
|
ctx.SetStatusCode(fasthttp.StatusExpectationFailed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
user.DiscordID = regUpdate.DiscordID
|
||||||
|
|
||||||
|
err = SaveUser(user)
|
||||||
|
if err != nil {
|
||||||
|
addErrorToCtx(ctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setResponseJson(ctx, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
func AppointmentPost(ctx *fasthttp.RequestCtx) {
|
func AppointmentPost(ctx *fasthttp.RequestCtx) {
|
||||||
@@ -409,7 +472,7 @@ func AppointmentPost(ctx *fasthttp.RequestCtx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ChatPost(ctx *fasthttp.RequestCtx) {
|
func ChatPost(ctx *fasthttp.RequestCtx) {
|
||||||
auth := ctx.Request.Header.Peek("X-HUSO-AUTH")
|
auth := ctx.Request.Header.Peek(xHusoAuth)
|
||||||
if ctx.UserValue("id") == nil || ctx.UserValue("user") == nil || auth == nil || string(auth) == "" || !strings.Contains(string(ctx.Request.Header.ContentType()), "text/plain") {
|
if ctx.UserValue("id") == nil || ctx.UserValue("user") == nil || auth == nil || string(auth) == "" || !strings.Contains(string(ctx.Request.Header.ContentType()), "text/plain") {
|
||||||
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@@ -450,7 +513,7 @@ func ChatPost(ctx *fasthttp.RequestCtx) {
|
|||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.SetContentType("text/plain; charset=utf-8")
|
ctx.SetContentType(textContentType)
|
||||||
ctx.SetStatusCode(fasthttp.StatusOK)
|
ctx.SetStatusCode(fasthttp.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,12 +521,17 @@ func WatchPost(ctx *fasthttp.RequestCtx) {
|
|||||||
processUpdateReq(ctx, true)
|
processUpdateReq(ctx, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UserStashPut(ctx *fasthttp.RequestCtx) {
|
||||||
|
processUserStashReq(ctx, true)
|
||||||
|
}
|
||||||
|
|
||||||
func AppointmentDelete(ctx *fasthttp.RequestCtx) {
|
func AppointmentDelete(ctx *fasthttp.RequestCtx) {
|
||||||
processUpdateAppointmentReq(ctx, false)
|
processUpdateAppointmentReq(ctx, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnRegister(ctx *fasthttp.RequestCtx) {
|
func UnRegister(ctx *fasthttp.RequestCtx) {
|
||||||
if !strings.Contains(string(ctx.Request.Header.ContentType()), "application/json") {
|
auth := ctx.Request.Header.Peek(xHusoAuth)
|
||||||
|
if auth == nil || string(auth) == "" || !strings.Contains(string(ctx.Request.Header.ContentType()), "application/json") {
|
||||||
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -480,6 +548,11 @@ func UnRegister(ctx *fasthttp.RequestCtx) {
|
|||||||
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
legit, _ := GheddoAuth(register.Username, string(auth))
|
||||||
|
if !legit {
|
||||||
|
ctx.SetStatusCode(fasthttp.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
calcSauce := Sauce(register.MalID, register.Username)
|
calcSauce := Sauce(register.MalID, register.Username)
|
||||||
if calcSauce != strings.ToLower(register.Sauce) {
|
if calcSauce != strings.ToLower(register.Sauce) {
|
||||||
ctx.WriteString("Möge die Sauce mit dir sein")
|
ctx.WriteString("Möge die Sauce mit dir sein")
|
||||||
@@ -508,9 +581,7 @@ func UnRegister(ctx *fasthttp.RequestCtx) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.SetBody(body)
|
setResponseJson(ctx, body)
|
||||||
ctx.SetContentType("application/json; charset=utf-8")
|
|
||||||
ctx.SetStatusCode(fasthttp.StatusOK)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func WatchDelete(ctx *fasthttp.RequestCtx) {
|
func WatchDelete(ctx *fasthttp.RequestCtx) {
|
||||||
@@ -573,11 +644,17 @@ func watchGetLogic(ctx *fasthttp.RequestCtx) ([]AnimeUser, error) {
|
|||||||
}
|
}
|
||||||
animesUsers = filteredAnimes
|
animesUsers = filteredAnimes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort.Slice(animesUsers, func(i, j int) bool { return animesUsers[i].Anime < animesUsers[j].Anime })
|
||||||
|
sort.SliceStable(animesUsers, func(i, j int) bool {
|
||||||
|
return AverageEpPerUser(animesUsers[i].Users) > AverageEpPerUser(animesUsers[j].Users)
|
||||||
|
})
|
||||||
|
|
||||||
return animesUsers, err
|
return animesUsers, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func processUpdateReq(ctx *fasthttp.RequestCtx, update bool) {
|
func processUpdateReq(ctx *fasthttp.RequestCtx, update bool) {
|
||||||
auth := ctx.Request.Header.Peek("X-HUSO-AUTH")
|
auth := ctx.Request.Header.Peek(xHusoAuth)
|
||||||
if ctx.UserValue("user") == nil || auth == nil || string(auth) == "" || !strings.Contains(string(ctx.Request.Header.ContentType()), "application/json") {
|
if ctx.UserValue("user") == nil || auth == nil || string(auth) == "" || !strings.Contains(string(ctx.Request.Header.ContentType()), "application/json") {
|
||||||
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@@ -593,7 +670,9 @@ func processUpdateReq(ctx *fasthttp.RequestCtx, update bool) {
|
|||||||
var animes []AnimeUser
|
var animes []AnimeUser
|
||||||
err := json.Unmarshal(body, &animes)
|
err := json.Unmarshal(body, &animes)
|
||||||
if err != nil || len(animes) == 0 {
|
if err != nil || len(animes) == 0 {
|
||||||
|
if err != nil {
|
||||||
ctx.WriteString(err.Error())
|
ctx.WriteString(err.Error())
|
||||||
|
}
|
||||||
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -613,7 +692,7 @@ func processUpdateReq(ctx *fasthttp.RequestCtx, update bool) {
|
|||||||
if update {
|
if update {
|
||||||
// anime exitsts => save
|
// anime exitsts => save
|
||||||
// get watch progress
|
// get watch progress
|
||||||
progress, updated, listState, _ := FetchProgress(anime.Anime, userId, username, 0)
|
progress, updated, _, listState, _ := FetchProgress(anime.Anime, username)
|
||||||
// anime is already completed big baka user
|
// anime is already completed big baka user
|
||||||
if listState == malApiStatusC {
|
if listState == malApiStatusC {
|
||||||
ctx.WriteString("Du hast schon fertig geschaut bro")
|
ctx.WriteString("Du hast schon fertig geschaut bro")
|
||||||
@@ -643,16 +722,11 @@ func processUpdateReq(ctx *fasthttp.RequestCtx, update bool) {
|
|||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = writeResponseBody(ctx, data)
|
setResponseJson(ctx, data)
|
||||||
if err != nil {
|
|
||||||
addErrorToCtx(ctx, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.SetContentType("application/json; charset=utf-8")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func processUpdateAppointmentReq(ctx *fasthttp.RequestCtx, update bool) {
|
func processUpdateAppointmentReq(ctx *fasthttp.RequestCtx, update bool) {
|
||||||
auth := ctx.Request.Header.Peek("X-HUSO-AUTH")
|
auth := ctx.Request.Header.Peek(xHusoAuth)
|
||||||
if ctx.UserValue("user") == nil || auth == nil || string(auth) == "" || !strings.Contains(string(ctx.Request.Header.ContentType()), "application/json") {
|
if ctx.UserValue("user") == nil || auth == nil || string(auth) == "" || !strings.Contains(string(ctx.Request.Header.ContentType()), "application/json") {
|
||||||
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@@ -668,7 +742,9 @@ func processUpdateAppointmentReq(ctx *fasthttp.RequestCtx, update bool) {
|
|||||||
var appoints []Appointment
|
var appoints []Appointment
|
||||||
err := json.Unmarshal(body, &appoints)
|
err := json.Unmarshal(body, &appoints)
|
||||||
if err != nil || len(appoints) == 0 {
|
if err != nil || len(appoints) == 0 {
|
||||||
|
if err != nil {
|
||||||
ctx.WriteString(err.Error())
|
ctx.WriteString(err.Error())
|
||||||
|
}
|
||||||
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -677,6 +753,7 @@ func processUpdateAppointmentReq(ctx *fasthttp.RequestCtx, update bool) {
|
|||||||
for i, appointment := range appoints {
|
for i, appointment := range appoints {
|
||||||
var appData *Appointment
|
var appData *Appointment
|
||||||
var found bool
|
var found bool
|
||||||
|
fresh := false
|
||||||
|
|
||||||
if update {
|
if update {
|
||||||
// kann sich (noch) nicht in der Vergagenheit verabreden
|
// kann sich (noch) nicht in der Vergagenheit verabreden
|
||||||
@@ -698,7 +775,7 @@ func processUpdateAppointmentReq(ctx *fasthttp.RequestCtx, update bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// save appointment and get list
|
// save appointment and get list
|
||||||
appData, err = AddUserToAppointment(username, appointment.Anime, appointment.Time)
|
appData, fresh, err = AddUserToAppointment(username, appointment.Anime, appointment.Time)
|
||||||
} else {
|
} else {
|
||||||
found, err = CheckAnimeExistInDb(appointment.Anime)
|
found, err = CheckAnimeExistInDb(appointment.Anime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -718,6 +795,10 @@ func processUpdateAppointmentReq(ctx *fasthttp.RequestCtx, update bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
appoints[i].Users = appData.Users
|
appoints[i].Users = appData.Users
|
||||||
|
|
||||||
|
if update && fresh {
|
||||||
|
SendAppointBroadcast(username, appData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := json.Marshal(appoints)
|
data, err := json.Marshal(appoints)
|
||||||
@@ -725,22 +806,58 @@ func processUpdateAppointmentReq(ctx *fasthttp.RequestCtx, update bool) {
|
|||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = writeResponseBody(ctx, data)
|
setResponseJson(ctx, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func processUserStashReq(ctx *fasthttp.RequestCtx, update bool) {
|
||||||
|
auth := ctx.Request.Header.Peek(xHusoAuth)
|
||||||
|
dataPath := fmt.Sprintf("%s", ctx.UserValue("data"))
|
||||||
|
if auth == nil || string(auth) == "" || dataPath == "" {
|
||||||
|
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
username := fmt.Sprintf("%s", ctx.UserValue("user"))
|
||||||
|
legit, _ := GheddoAuth(username, string(auth))
|
||||||
|
if !legit {
|
||||||
|
ctx.SetStatusCode(fasthttp.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if update {
|
||||||
|
compressed, err := CompressZstd(ctx.PostBody())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
addErrorToCtx(ctx, err)
|
addErrorToCtx(ctx, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.SetContentType("application/json; charset=utf-8")
|
err = DbSave(bucketStash, fmt.Sprintf("%s.%s", username, dataPath), compressed)
|
||||||
|
if err != nil {
|
||||||
|
addErrorToCtx(ctx, err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeResponseBody(ctx *fasthttp.RequestCtx, bytes []byte) error {
|
ctx.SetStatusCode(fasthttp.StatusAccepted)
|
||||||
_, err := ctx.Write(bytes)
|
} else {
|
||||||
|
compressed, err := DbRead(bucketStash, []byte(fmt.Sprintf("%s.%s", username, dataPath)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
addErrorToCtx(ctx, err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
ctx.SetContentType("application/json; charset=utf-8")
|
decompressed, err := DecompressZstd(compressed)
|
||||||
|
if err != nil {
|
||||||
|
addErrorToCtx(ctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.SetBody(decompressed)
|
||||||
|
ctx.SetStatusCode(fasthttp.StatusOK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setResponseJson(ctx *fasthttp.RequestCtx, bytes []byte) {
|
||||||
|
ctx.SetBody(bytes)
|
||||||
|
ctx.SetContentType(jsonContentType)
|
||||||
ctx.SetStatusCode(fasthttp.StatusOK)
|
ctx.SetStatusCode(fasthttp.StatusOK)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addErrorToCtx(ctx *fasthttp.RequestCtx, err error) {
|
func addErrorToCtx(ctx *fasthttp.RequestCtx, err error) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Arbeiten() {
|
func Arbeiten() {
|
||||||
for range time.Tick(time.Hour) {
|
for range time.Tick(10 * time.Minute) {
|
||||||
Arbeit()
|
Arbeit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,8 +27,11 @@ func Arbeit() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cleared := 0
|
cleared := 0
|
||||||
|
lastAnnounce.Lock()
|
||||||
|
defer lastAnnounce.Unlock()
|
||||||
|
newCheckDate := time.Now()
|
||||||
for _, a := range appoints {
|
for _, a := range appoints {
|
||||||
if a.Time.Before(time.Now()) {
|
if a.Time.Add(22 * time.Hour).Before(newCheckDate) {
|
||||||
// appointment expired
|
// appointment expired
|
||||||
keyBytes := Int64AndDateToBytes(a.Anime, a.Time)
|
keyBytes := Int64AndDateToBytes(a.Anime, a.Time)
|
||||||
err = DbDelete(bucketAppoint, string(keyBytes))
|
err = DbDelete(bucketAppoint, string(keyBytes))
|
||||||
@@ -38,8 +41,14 @@ func Arbeit() {
|
|||||||
} else {
|
} else {
|
||||||
cleared++
|
cleared++
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if lastAnnounce.stamp.Add(time.Hour).Before(a.Time) && newCheckDate.Add(time.Hour).After(a.Time) {
|
||||||
|
// This has not happened and is happening soon
|
||||||
|
go AnnounceBomb(a.Anime, a.Time.Unix(), time.Until(a.Time.Add(-25*time.Minute)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
lastAnnounce.stamp = newCheckDate
|
||||||
if cleared > 0 {
|
if cleared > 0 {
|
||||||
color.Infof("Cleared %d expired appointments\n", cleared)
|
color.Infof("Cleared %d expired appointments\n", cleared)
|
||||||
logOut.WriteLine(fmt.Sprintf("♻️ Cleared %d expired appointments", cleared))
|
logOut.WriteLine(fmt.Sprintf("♻️ Cleared %d expired appointments", cleared))
|
||||||
@@ -55,11 +64,19 @@ func Arbeit() {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ACTUALLY STUPID ENOUGH TO FIX A LOT OF PROBLEMS
|
||||||
|
animeListCache.Reset()
|
||||||
|
|
||||||
|
color.Infoln("Animelisten abfragen...")
|
||||||
|
//logOut.WriteLine("📜 Animelisten abfragen...")
|
||||||
|
|
||||||
|
count := 0
|
||||||
// iterate anime
|
// iterate anime
|
||||||
for _, a := range animesUsers {
|
for _, a := range animesUsers {
|
||||||
// iterate users
|
// iterate users
|
||||||
for _, u := range a.Users {
|
for _, u := range a.Users {
|
||||||
newProgress, updated, listState, err := FetchProgress(a.Anime, u.MalID, u.Username, u.Progress)
|
newProgress, updated, score, listState, err := FetchProgress(a.Anime, u.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
color.Errorln(err.Error())
|
color.Errorln(err.Error())
|
||||||
logOut.WriteError(err)
|
logOut.WriteError(err)
|
||||||
@@ -67,41 +84,49 @@ func Arbeit() {
|
|||||||
}
|
}
|
||||||
// check if user set anime as completed
|
// check if user set anime as completed
|
||||||
if listState == malApiStatusC {
|
if listState == malApiStatusC {
|
||||||
color.Infof("%s finished %d\n", u.Username, a.Anime)
|
color.Infof("%s finished %d scored %d\n", u.Username, a.Anime, score)
|
||||||
logOut.WriteLine(fmt.Sprintf("📜 %s finished %d !", u.Username, a.Anime))
|
logOut.WriteLine(fmt.Sprintf("📝 %s finished %d scored %d !", u.Username, a.Anime, score))
|
||||||
// delete user from anime
|
// delete user from anime
|
||||||
_, err = DeleteUserFromAnime(u.Username, u.MalID, a.Anime)
|
_, err = DeleteUserFromAnime(u.Username, u.MalID, a.Anime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
color.Errorln(err.Error())
|
color.Errorln(err.Error())
|
||||||
logOut.WriteError(err)
|
logOut.WriteError(err)
|
||||||
}
|
}
|
||||||
|
count++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// check if user set anime as dropped
|
// check if user set anime as dropped
|
||||||
if listState == malApiStatusD {
|
if listState == malApiStatusD {
|
||||||
color.Infof("%s dropped %d\n", u.Username, a.Anime)
|
color.Infof("%s dropped %d\n", u.Username, a.Anime)
|
||||||
logOut.WriteLine(fmt.Sprintf("📜 %s dropped %d !", u.Username, a.Anime))
|
logOut.WriteLine(fmt.Sprintf("📝 %s dropped %d !", u.Username, a.Anime))
|
||||||
// delete user from anime
|
// delete user from anime
|
||||||
_, err = DeleteUserFromAnime(u.Username, u.MalID, a.Anime)
|
_, err = DeleteUserFromAnime(u.Username, u.MalID, a.Anime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
color.Errorln(err.Error())
|
color.Errorln(err.Error())
|
||||||
logOut.WriteError(err)
|
logOut.WriteError(err)
|
||||||
}
|
}
|
||||||
|
count++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if newProgress == u.Progress {
|
if newProgress == u.Progress {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
color.Infof("%s progress von %d: %d -> %d\n", u.Username, a.Anime, u.Progress, newProgress)
|
color.Infof("%s progress von %d: %d -> %d\n", u.Username, a.Anime, u.Progress, newProgress)
|
||||||
logOut.WriteLine(fmt.Sprintf("📜 %s progress von %d: %d -> %d", u.Username, a.Anime, u.Progress, newProgress))
|
logOut.WriteLine(fmt.Sprintf("📝 %s progress von %d: %d -> %d", u.Username, a.Anime, u.Progress, newProgress))
|
||||||
// update db
|
// update db
|
||||||
err = UpdateUserAnimeProgress(a.Anime, u.MalID, newProgress, updated)
|
err = UpdateUserAnimeProgress(a.Anime, u.MalID, newProgress, updated)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
color.Errorln(err.Error())
|
color.Errorln(err.Error())
|
||||||
logOut.WriteError(err)
|
logOut.WriteError(err)
|
||||||
}
|
}
|
||||||
|
count++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
color.Infof("%d Sachen aktualisiert\n", count)
|
||||||
|
logOut.WriteLine(fmt.Sprintf("📜 %d Sachen aktualisiert", count))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BissleArbeiten() {
|
func BissleArbeiten() {
|
||||||
@@ -122,7 +147,7 @@ func BissleArbeit() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, u := range regUsers {
|
for _, u := range regUsers {
|
||||||
_, _, err = GetUserData(u.Username)
|
err = refreshUser(u.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
color.Errorln(err.Error())
|
color.Errorln(err.Error())
|
||||||
logOut.WriteError(err)
|
logOut.WriteError(err)
|
||||||
@@ -143,30 +168,31 @@ func LangeArbeiten() {
|
|||||||
|
|
||||||
func LangeArbeit() {
|
func LangeArbeit() {
|
||||||
// season data
|
// season data
|
||||||
_, bytes, err := GetSeasonDataAll()
|
err := refreshSeason(GetCurrentSeasonString())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
color.Errorln(err.Error())
|
color.Errorln(err.Error())
|
||||||
logOut.WriteError(err)
|
logOut.WriteError(err)
|
||||||
} else {
|
|
||||||
err = seasoncache.Set(seasonApiJikan, bytes)
|
|
||||||
if err != nil {
|
|
||||||
color.Errorln(err.Error())
|
|
||||||
logOut.WriteError(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// next season data
|
// next season data
|
||||||
nextSeason := GetNextSeasonString()
|
err = refreshSeason(GetNextSeasonString())
|
||||||
_, bytes, err = GetNextSeasonDataAll(nextSeason)
|
|
||||||
if err != nil {
|
|
||||||
color.Errorln(err.Error())
|
|
||||||
logOut.WriteError(err)
|
|
||||||
} else {
|
|
||||||
err = seasoncache.Set(nextSeason, bytes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
color.Errorln(err.Error())
|
color.Errorln(err.Error())
|
||||||
logOut.WriteError(err)
|
logOut.WriteError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// next next season data
|
||||||
|
err = refreshSeason(GetNextNextSeasonString())
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
logOut.WriteError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// last season data
|
||||||
|
err = refreshSeason(GetLastSeasonString())
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
logOut.WriteError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// refresh anime cache with watched
|
// refresh anime cache with watched
|
||||||
@@ -179,8 +205,8 @@ func LangeArbeit() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, a := range animesUsers {
|
for _, a := range animesUsers {
|
||||||
// search season first
|
// search seasons first
|
||||||
_, err = SearchSeason(a.Anime)
|
_, err = SearchSeasons(a.Anime)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -225,6 +251,21 @@ func refreshAnime(animeId int64) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
animeCache.Set(key, data)
|
return animeCache.Set(key, data)
|
||||||
return nil
|
}
|
||||||
|
|
||||||
|
func refreshSeason(season string) error {
|
||||||
|
_, bytes, err := GetSeasonDataAll(season)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return seasoncache.Set(season, bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func refreshUser(username string) error {
|
||||||
|
_, data, err := GetUserData(username)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return userCache.Set(username, data)
|
||||||
}
|
}
|
||||||
|
|||||||
44
rechner.go
44
rechner.go
@@ -1,12 +1,16 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/klauspost/compress/zstd"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Sauce(malid int64, username string) string {
|
func Sauce(malid int64, username string) string {
|
||||||
@@ -43,3 +47,43 @@ func BytesToInt64AndDate(bytes []byte) (int64, time.Time, error) {
|
|||||||
func Int64AndDateToBytes(num int64, appoint time.Time) []byte {
|
func Int64AndDateToBytes(num int64, appoint time.Time) []byte {
|
||||||
return []byte(fmt.Sprintf("%d%s%s", num, AppointSplit, appoint.Format(time.RFC3339)))
|
return []byte(fmt.Sprintf("%d%s%s", num, AppointSplit, appoint.Format(time.RFC3339)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CompressZstd(src []byte) ([]byte, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
encoder, err := zstd.NewWriter(&buf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
reader := bytes.NewReader(src)
|
||||||
|
_, err = io.Copy(encoder, reader)
|
||||||
|
if err != nil {
|
||||||
|
encoder.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = encoder.Close()
|
||||||
|
return buf.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecompressZstd(src []byte) ([]byte, error) {
|
||||||
|
reader := bytes.NewReader(src)
|
||||||
|
decoder, err := zstd.NewReader(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer decoder.Close()
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_, err = io.Copy(&buf, decoder)
|
||||||
|
return buf.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func AverageEpPerUser(users []WatchUser) float64 {
|
||||||
|
if len(users) == 0 {
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
res := 0.0
|
||||||
|
for _, u := range users {
|
||||||
|
res += float64(u.Progress)
|
||||||
|
}
|
||||||
|
return res / float64(len(users))
|
||||||
|
}
|
||||||
|
|||||||
149
schaffer.go
149
schaffer.go
@@ -4,9 +4,11 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gookit/color"
|
||||||
"github.com/xujiajun/nutsdb"
|
"github.com/xujiajun/nutsdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -121,14 +123,11 @@ func GetSeasonCache(key string) ([]Anime, error) {
|
|||||||
return seasonData, err
|
return seasonData, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func SearchSeason(animeId int64) (*Anime, error) {
|
func SearchSeasons(animeId int64) (*Anime, error) {
|
||||||
season, err := GetSeasonCache(seasonApiJikan)
|
season, err := GetSeasonCache(GetCurrentSeasonString())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(season) == 0 {
|
|
||||||
return nil, errors.New("no seasonal anime")
|
|
||||||
}
|
|
||||||
for _, a := range season {
|
for _, a := range season {
|
||||||
if a.Anime == animeId {
|
if a.Anime == animeId {
|
||||||
return &a, err
|
return &a, err
|
||||||
@@ -138,8 +137,23 @@ func SearchSeason(animeId int64) (*Anime, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(season) == 0 {
|
for _, a := range season {
|
||||||
return nil, errors.New("no seasonal anime")
|
if a.Anime == animeId {
|
||||||
|
return &a, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
season, err = GetSeasonCache(GetNextNextSeasonString())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, a := range season {
|
||||||
|
if a.Anime == animeId {
|
||||||
|
return &a, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
season, err = GetSeasonCache(GetLastSeasonString())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, a := range season {
|
for _, a := range season {
|
||||||
if a.Anime == animeId {
|
if a.Anime == animeId {
|
||||||
@@ -151,7 +165,7 @@ func SearchSeason(animeId int64) (*Anime, error) {
|
|||||||
|
|
||||||
func SearchAnime(animeId int64) (*Anime, error) {
|
func SearchAnime(animeId int64) (*Anime, error) {
|
||||||
// search season first
|
// search season first
|
||||||
anime, err := SearchSeason(animeId)
|
anime, err := SearchSeasons(animeId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// get from MAL
|
// get from MAL
|
||||||
anime, _, err = GetAnimeDetailData(animeId)
|
anime, _, err = GetAnimeDetailData(animeId)
|
||||||
@@ -180,57 +194,56 @@ func SearchAppointments(animeId int64) ([]Appointment, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FetchProgress(animeId, userId int64, username string, progress int) (int, time.Time, string, error) {
|
func FetchProgress(animeId int64, username string) (int, time.Time, int, string, error) {
|
||||||
// check watching first
|
// check watching first
|
||||||
newProgress, updated, err := fetchProgressOnState(animeId, userId, progress, username, malApiStatusW)
|
newProgress, updated, score, err := FetchProgressOnState(animeId, username, malApiStatusW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return newProgress, updated, "", err
|
return newProgress, updated, score, "", err
|
||||||
}
|
}
|
||||||
if newProgress != -1 {
|
if newProgress != -1 {
|
||||||
return newProgress, updated, malApiStatusW, err
|
return newProgress, updated, score, malApiStatusW, err
|
||||||
}
|
|
||||||
// check on hold
|
|
||||||
newProgress, updated, err = fetchProgressOnState(animeId, userId, progress, username, malApiStatusH)
|
|
||||||
if err != nil {
|
|
||||||
return newProgress, updated, "", err
|
|
||||||
}
|
|
||||||
if newProgress != -1 {
|
|
||||||
return newProgress, updated, malApiStatusH, err
|
|
||||||
}
|
}
|
||||||
// check completed
|
// check completed
|
||||||
newProgress, updated, err = fetchProgressOnState(animeId, userId, progress, username, malApiStatusC)
|
newProgress, updated, score, err = FetchProgressOnState(animeId, username, malApiStatusC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return newProgress, updated, "", err
|
return newProgress, updated, score, "", err
|
||||||
}
|
}
|
||||||
if newProgress != -1 {
|
if newProgress != -1 {
|
||||||
return newProgress, updated, malApiStatusC, err
|
return newProgress, updated, score, malApiStatusC, err
|
||||||
|
}
|
||||||
|
// check on hold
|
||||||
|
newProgress, updated, score, err = FetchProgressOnState(animeId, username, malApiStatusH)
|
||||||
|
if err != nil {
|
||||||
|
return newProgress, updated, score, "", err
|
||||||
|
}
|
||||||
|
if newProgress != -1 {
|
||||||
|
return newProgress, updated, score, malApiStatusH, err
|
||||||
}
|
}
|
||||||
// check dropped
|
// check dropped
|
||||||
newProgress, updated, err = fetchProgressOnState(animeId, userId, progress, username, malApiStatusD)
|
newProgress, updated, score, err = FetchProgressOnState(animeId, username, malApiStatusD)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return newProgress, updated, "", err
|
return newProgress, updated, score, "", err
|
||||||
}
|
}
|
||||||
if newProgress != -1 {
|
if newProgress != -1 {
|
||||||
return newProgress, updated, malApiStatusD, err
|
return newProgress, updated, score, malApiStatusD, err
|
||||||
}
|
}
|
||||||
// has no progress or PTW
|
// has no progress or PTW
|
||||||
return 0, updated, "", nil
|
return 0, updated, 0, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchProgressOnState(animeId, userId int64, progress int, username, malStatus string) (int, time.Time, error) {
|
func FetchProgressOnState(animeId int64, username, malStatus string) (int, time.Time, int, error) {
|
||||||
list, _, err := GetUserAnimeListData(username, malStatus)
|
list, _, err := GetUserAnimeListData(username, malStatus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, time.Time{}, err
|
return 0, time.Time{}, 0, err
|
||||||
}
|
}
|
||||||
for _, a := range list.Data {
|
for _, a := range list.Data {
|
||||||
// check if found
|
// check if found
|
||||||
if a.Node.ID == animeId {
|
if a.Node.ID == animeId {
|
||||||
// check if progress changed
|
return a.ListStatus.NumEpisodesWatched, a.ListStatus.UpdatedAt, a.ListStatus.Score, nil
|
||||||
return a.ListStatus.NumEpisodesWatched, a.ListStatus.UpdatedAt, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// no progess found
|
// no progess found
|
||||||
return -1, time.Now(), nil
|
return -1, time.Now(), 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddToChat(old, new, user string) string {
|
func AddToChat(old, new, user string) string {
|
||||||
@@ -240,6 +253,19 @@ func AddToChat(old, new, user string) string {
|
|||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetAnimeWatchFromDb(animeId int64) (*AnimeUser, error) {
|
||||||
|
dbAnime, err := ReadAnimeUsers()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, a := range dbAnime {
|
||||||
|
if a.Anime == animeId {
|
||||||
|
return &a, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("anime not found")
|
||||||
|
}
|
||||||
|
|
||||||
func CheckAnimeExistInDb(animeId int64) (bool, error) {
|
func CheckAnimeExistInDb(animeId int64) (bool, error) {
|
||||||
dbAnime, err := ReadAnimeUsers()
|
dbAnime, err := ReadAnimeUsers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -270,3 +296,62 @@ func CheckAnimeExistInDbAndUserWatches(animeId, userId int64) (bool, error) {
|
|||||||
}
|
}
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BuildMovieCharts() ([]MovieChart, error) {
|
||||||
|
key := "charts"
|
||||||
|
var charts []MovieChart
|
||||||
|
data, err := mmCache.Get(key)
|
||||||
|
if err == nil {
|
||||||
|
err = json.Unmarshal(data, &charts)
|
||||||
|
if err == nil {
|
||||||
|
return charts, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
movieList, err := MmReadCharts()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
users, err := ReadRegisteredUsers()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
charts = make([]MovieChart, 0)
|
||||||
|
for _, m := range movieList {
|
||||||
|
c := MovieChart{
|
||||||
|
MmId: m.Id,
|
||||||
|
Anime: m.Anime,
|
||||||
|
Title: m.Title,
|
||||||
|
}
|
||||||
|
|
||||||
|
scoreSum := 0
|
||||||
|
for _, u := range users {
|
||||||
|
progress, _, score, err := FetchProgressOnState(c.Anime, u.Username, malApiStatusC)
|
||||||
|
if err != nil {
|
||||||
|
color.Errorln(err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if progress == -1 || score == 0 {
|
||||||
|
// user has no progress/score
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
scoreSum += score
|
||||||
|
c.UserCount++
|
||||||
|
}
|
||||||
|
if c.UserCount > 0 {
|
||||||
|
c.AvgScore = float64(scoreSum) / float64(c.UserCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
charts = append(charts, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.SliceStable(charts, func(i, j int) bool { return charts[i].AvgScore > charts[j].AvgScore })
|
||||||
|
|
||||||
|
bytes, err := json.Marshal(charts)
|
||||||
|
if err == nil {
|
||||||
|
mmCache.Set(key, bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return charts, nil
|
||||||
|
}
|
||||||
|
|||||||
53
season.qtpl
53
season.qtpl
@@ -1,5 +1,5 @@
|
|||||||
{% package main %}
|
{% package main %}
|
||||||
{% func Index(animes []Anime, log string) %}
|
{% func Index(animes []Anime, oracles []MmOracle, charts []MovieChart, log string) %}
|
||||||
{% collapsespace %}
|
{% collapsespace %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@@ -19,6 +19,8 @@ body { background-color: #1a1a1a; color: #fff; }
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>HUSO - Hanami universeller Serien Organizer</h1>
|
<h1>HUSO - Hanami universeller Serien Organizer</h1>
|
||||||
|
<h2>Log</h2>
|
||||||
|
<pre>{%s log %}</pre>
|
||||||
<h2>Anime</h2>
|
<h2>Anime</h2>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -28,18 +30,55 @@ body { background-color: #1a1a1a; color: #fff; }
|
|||||||
</table>
|
</table>
|
||||||
</br>
|
</br>
|
||||||
<table>
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>MALID</th>
|
||||||
|
<th>SCORE</th>
|
||||||
|
<th>TITLE</th>
|
||||||
|
</tr>
|
||||||
{% for _, anime := range animes %}
|
{% for _, anime := range animes %}
|
||||||
<tr>
|
<tr>
|
||||||
|
<td><a href="{%s anime.URL %}" target="_blank" rel="noopener noreferrer">{%dl anime.Anime %}</a></td>
|
||||||
|
<td>{%f.2 anime.Score %}</td>
|
||||||
<td><strong>{%s anime.Title %}</strong></td>
|
<td><strong>{%s anime.Title %}</strong></td>
|
||||||
<td>{%dl anime.Anime %}</td>
|
|
||||||
<td>{%d anime.Episodes %}</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
<h2>Log</h2>
|
<h2>MovieManager Charts</h2>
|
||||||
<pre>
|
<table>
|
||||||
{%s log %}
|
<tr>
|
||||||
</pre>
|
<th>MMID</th>
|
||||||
|
<th>MALID</th>
|
||||||
|
<th>USER</th>
|
||||||
|
<th>SCORE</th>
|
||||||
|
<th>TITLE</th>
|
||||||
|
</tr>
|
||||||
|
{% for _, chart := range charts %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="https://movies.hanami.family/movie/{%d chart.MmId %}" target="_blank" rel="noopener noreferrer">{%d chart.MmId %}</a></td>
|
||||||
|
<td><a href="https://myanimelist.net/anime/{%dl chart.Anime %}" target="_blank" rel="noopener noreferrer">{%dl chart.Anime %}</a></td>
|
||||||
|
<td>{%d chart.UserCount %}</td>
|
||||||
|
<td><strong>{%f.2 chart.AvgScore %}</strong></td>
|
||||||
|
<td><strong>{%s chart.Title %}</strong></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
<h2>MovieManager Oracle</h2>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>MMID</th>
|
||||||
|
<th>MALID</th>
|
||||||
|
<th>SCORE</th>
|
||||||
|
<th>TITLE</th>
|
||||||
|
</tr>
|
||||||
|
{% for _, oracle := range oracles %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="https://movies.hanami.family/movie/{%d oracle.Id %}" target="_blank" rel="noopener noreferrer">{%d oracle.Id %}</a></td>
|
||||||
|
<td>{%dl oracle.Anime %}</td>
|
||||||
|
<td>{%d oracle.AvgScore %}</td>
|
||||||
|
<td><strong>{%s oracle.Title %}</strong></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
{% endcollapsespace %}
|
{% endcollapsespace %}
|
||||||
|
|||||||
160
season.qtpl.go
160
season.qtpl.go
@@ -18,68 +18,136 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
//line season.qtpl:2
|
//line season.qtpl:2
|
||||||
func StreamIndex(qw422016 *qt422016.Writer, animes []Anime, log string) {
|
func StreamIndex(qw422016 *qt422016.Writer, animes []Anime, oracles []MmOracle, charts []MovieChart, log string) {
|
||||||
//line season.qtpl:2
|
//line season.qtpl:2
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
`)
|
`)
|
||||||
//line season.qtpl:3
|
//line season.qtpl:3
|
||||||
qw422016.N().S(` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> * { font-family: sans-serif; } table { border-spacing: 0; } td, th { text-align: left; padding: 0 0.5em; } td:first-child, th:first-child { padding-left: 0; } td:last-child, th:first-child { padding-right: 0; } body { background-color: #1a1a1a; color: #fff; } </style> <title>HUSO - Hanami universeller Serien Organizer</title> </head> <body> <h1>HUSO - Hanami universeller Serien Organizer</h1> <h2>Anime</h2> <table> <tr> <td><strong>Airing 📺</strong></td> <td>`)
|
qw422016.N().S(` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> * { font-family: sans-serif; } table { border-spacing: 0; } td, th { text-align: left; padding: 0 0.5em; } td:first-child, th:first-child { padding-left: 0; } td:last-child, th:first-child { padding-right: 0; } body { background-color: #1a1a1a; color: #fff; } </style> <title>HUSO - Hanami universeller Serien Organizer</title> </head> <body> <h1>HUSO - Hanami universeller Serien Organizer</h1> <h2>Log</h2> <pre>`)
|
||||||
//line season.qtpl:26
|
//line season.qtpl:23
|
||||||
qw422016.N().D(len(animes))
|
|
||||||
//line season.qtpl:26
|
|
||||||
qw422016.N().S(`</td> </tr> </table> </br> <table> `)
|
|
||||||
//line season.qtpl:31
|
|
||||||
for _, anime := range animes {
|
|
||||||
//line season.qtpl:31
|
|
||||||
qw422016.N().S(` <tr> <td><strong>`)
|
|
||||||
//line season.qtpl:33
|
|
||||||
qw422016.E().S(anime.Title)
|
|
||||||
//line season.qtpl:33
|
|
||||||
qw422016.N().S(`</strong></td> <td>`)
|
|
||||||
//line season.qtpl:34
|
|
||||||
qw422016.N().DL(anime.Anime)
|
|
||||||
//line season.qtpl:34
|
|
||||||
qw422016.N().S(`</td> <td>`)
|
|
||||||
//line season.qtpl:35
|
|
||||||
qw422016.N().D(anime.Episodes)
|
|
||||||
//line season.qtpl:35
|
|
||||||
qw422016.N().S(`</td> </tr> `)
|
|
||||||
//line season.qtpl:37
|
|
||||||
}
|
|
||||||
//line season.qtpl:37
|
|
||||||
qw422016.N().S(` </table> <h2>Log</h2> <pre> `)
|
|
||||||
//line season.qtpl:41
|
|
||||||
qw422016.E().S(log)
|
qw422016.E().S(log)
|
||||||
|
//line season.qtpl:23
|
||||||
|
qw422016.N().S(`</pre> <h2>Anime</h2> <table> <tr> <td><strong>Airing 📺</strong></td> <td>`)
|
||||||
|
//line season.qtpl:28
|
||||||
|
qw422016.N().D(len(animes))
|
||||||
|
//line season.qtpl:28
|
||||||
|
qw422016.N().S(`</td> </tr> </table> </br> <table> <tr> <th>MALID</th> <th>SCORE</th> <th>TITLE</th> </tr> `)
|
||||||
|
//line season.qtpl:38
|
||||||
|
for _, anime := range animes {
|
||||||
|
//line season.qtpl:38
|
||||||
|
qw422016.N().S(` <tr> <td><a href="`)
|
||||||
|
//line season.qtpl:40
|
||||||
|
qw422016.E().S(anime.URL)
|
||||||
|
//line season.qtpl:40
|
||||||
|
qw422016.N().S(`" target="_blank" rel="noopener noreferrer">`)
|
||||||
|
//line season.qtpl:40
|
||||||
|
qw422016.N().DL(anime.Anime)
|
||||||
|
//line season.qtpl:40
|
||||||
|
qw422016.N().S(`</a></td> <td>`)
|
||||||
//line season.qtpl:41
|
//line season.qtpl:41
|
||||||
qw422016.N().S(` </pre> </body> </html> `)
|
qw422016.N().FPrec(anime.Score, 2)
|
||||||
//line season.qtpl:45
|
//line season.qtpl:41
|
||||||
|
qw422016.N().S(`</td> <td><strong>`)
|
||||||
|
//line season.qtpl:42
|
||||||
|
qw422016.E().S(anime.Title)
|
||||||
|
//line season.qtpl:42
|
||||||
|
qw422016.N().S(`</strong></td> </tr> `)
|
||||||
|
//line season.qtpl:44
|
||||||
|
}
|
||||||
|
//line season.qtpl:44
|
||||||
|
qw422016.N().S(` </table> <h2>MovieManager Charts</h2> <table> <tr> <th>MMID</th> <th>MALID</th> <th>USER</th> <th>SCORE</th> <th>TITLE</th> </tr> `)
|
||||||
|
//line season.qtpl:55
|
||||||
|
for _, chart := range charts {
|
||||||
|
//line season.qtpl:55
|
||||||
|
qw422016.N().S(` <tr> <td><a href="https://movies.hanami.family/movie/`)
|
||||||
|
//line season.qtpl:57
|
||||||
|
qw422016.N().D(chart.MmId)
|
||||||
|
//line season.qtpl:57
|
||||||
|
qw422016.N().S(`" target="_blank" rel="noopener noreferrer">`)
|
||||||
|
//line season.qtpl:57
|
||||||
|
qw422016.N().D(chart.MmId)
|
||||||
|
//line season.qtpl:57
|
||||||
|
qw422016.N().S(`</a></td> <td><a href="https://myanimelist.net/anime/`)
|
||||||
|
//line season.qtpl:58
|
||||||
|
qw422016.N().DL(chart.Anime)
|
||||||
|
//line season.qtpl:58
|
||||||
|
qw422016.N().S(`" target="_blank" rel="noopener noreferrer">`)
|
||||||
|
//line season.qtpl:58
|
||||||
|
qw422016.N().DL(chart.Anime)
|
||||||
|
//line season.qtpl:58
|
||||||
|
qw422016.N().S(`</a></td> <td>`)
|
||||||
|
//line season.qtpl:59
|
||||||
|
qw422016.N().D(chart.UserCount)
|
||||||
|
//line season.qtpl:59
|
||||||
|
qw422016.N().S(`</td> <td><strong>`)
|
||||||
|
//line season.qtpl:60
|
||||||
|
qw422016.N().FPrec(chart.AvgScore, 2)
|
||||||
|
//line season.qtpl:60
|
||||||
|
qw422016.N().S(`</strong></td> <td><strong>`)
|
||||||
|
//line season.qtpl:61
|
||||||
|
qw422016.E().S(chart.Title)
|
||||||
|
//line season.qtpl:61
|
||||||
|
qw422016.N().S(`</strong></td> </tr> `)
|
||||||
|
//line season.qtpl:63
|
||||||
|
}
|
||||||
|
//line season.qtpl:63
|
||||||
|
qw422016.N().S(` </table> <h2>MovieManager Oracle</h2> <table> <tr> <th>MMID</th> <th>MALID</th> <th>SCORE</th> <th>TITLE</th> </tr> `)
|
||||||
|
//line season.qtpl:73
|
||||||
|
for _, oracle := range oracles {
|
||||||
|
//line season.qtpl:73
|
||||||
|
qw422016.N().S(` <tr> <td><a href="https://movies.hanami.family/movie/`)
|
||||||
|
//line season.qtpl:75
|
||||||
|
qw422016.N().D(oracle.Id)
|
||||||
|
//line season.qtpl:75
|
||||||
|
qw422016.N().S(`" target="_blank" rel="noopener noreferrer">`)
|
||||||
|
//line season.qtpl:75
|
||||||
|
qw422016.N().D(oracle.Id)
|
||||||
|
//line season.qtpl:75
|
||||||
|
qw422016.N().S(`</a></td> <td>`)
|
||||||
|
//line season.qtpl:76
|
||||||
|
qw422016.N().DL(oracle.Anime)
|
||||||
|
//line season.qtpl:76
|
||||||
|
qw422016.N().S(`</td> <td>`)
|
||||||
|
//line season.qtpl:77
|
||||||
|
qw422016.N().D(oracle.AvgScore)
|
||||||
|
//line season.qtpl:77
|
||||||
|
qw422016.N().S(`</td> <td><strong>`)
|
||||||
|
//line season.qtpl:78
|
||||||
|
qw422016.E().S(oracle.Title)
|
||||||
|
//line season.qtpl:78
|
||||||
|
qw422016.N().S(`</strong></td> </tr> `)
|
||||||
|
//line season.qtpl:80
|
||||||
|
}
|
||||||
|
//line season.qtpl:80
|
||||||
|
qw422016.N().S(` </table> </body> </html> `)
|
||||||
|
//line season.qtpl:84
|
||||||
qw422016.N().S(`
|
qw422016.N().S(`
|
||||||
`)
|
`)
|
||||||
//line season.qtpl:46
|
//line season.qtpl:85
|
||||||
}
|
}
|
||||||
|
|
||||||
//line season.qtpl:46
|
//line season.qtpl:85
|
||||||
func WriteIndex(qq422016 qtio422016.Writer, animes []Anime, log string) {
|
func WriteIndex(qq422016 qtio422016.Writer, animes []Anime, oracles []MmOracle, charts []MovieChart, log string) {
|
||||||
//line season.qtpl:46
|
//line season.qtpl:85
|
||||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||||
//line season.qtpl:46
|
//line season.qtpl:85
|
||||||
StreamIndex(qw422016, animes, log)
|
StreamIndex(qw422016, animes, oracles, charts, log)
|
||||||
//line season.qtpl:46
|
//line season.qtpl:85
|
||||||
qt422016.ReleaseWriter(qw422016)
|
qt422016.ReleaseWriter(qw422016)
|
||||||
//line season.qtpl:46
|
//line season.qtpl:85
|
||||||
}
|
}
|
||||||
|
|
||||||
//line season.qtpl:46
|
//line season.qtpl:85
|
||||||
func Index(animes []Anime, log string) string {
|
func Index(animes []Anime, oracles []MmOracle, charts []MovieChart, log string) string {
|
||||||
//line season.qtpl:46
|
//line season.qtpl:85
|
||||||
qb422016 := qt422016.AcquireByteBuffer()
|
qb422016 := qt422016.AcquireByteBuffer()
|
||||||
//line season.qtpl:46
|
//line season.qtpl:85
|
||||||
WriteIndex(qb422016, animes, log)
|
WriteIndex(qb422016, animes, oracles, charts, log)
|
||||||
//line season.qtpl:46
|
//line season.qtpl:85
|
||||||
qs422016 := string(qb422016.B)
|
qs422016 := string(qb422016.B)
|
||||||
//line season.qtpl:46
|
//line season.qtpl:85
|
||||||
qt422016.ReleaseByteBuffer(qb422016)
|
qt422016.ReleaseByteBuffer(qb422016)
|
||||||
//line season.qtpl:46
|
//line season.qtpl:85
|
||||||
return qs422016
|
return qs422016
|
||||||
//line season.qtpl:46
|
//line season.qtpl:85
|
||||||
}
|
}
|
||||||
|
|||||||
2
template.sh
Executable file
2
template.sh
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
~/go/bin/qtc
|
||||||
122
zecke.go
Normal file
122
zecke.go
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
_ "embed"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed mm.cred
|
||||||
|
var mmDbCred string
|
||||||
|
|
||||||
|
func GetMmConnString() (string, error) {
|
||||||
|
pw, err := base64.StdEncoding.DecodeString(mmDbCred)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s:%s@tcp(%s)/moviemanager?parseTime=true", *mmDbUser, pw, *mmDbServer), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func MmReadOracle() ([]MmOracle, error) {
|
||||||
|
key := "oracle"
|
||||||
|
var oracles []MmOracle
|
||||||
|
data, err := mmCache.Get(key)
|
||||||
|
if err == nil {
|
||||||
|
err = json.Unmarshal(data, &oracles)
|
||||||
|
if err == nil {
|
||||||
|
return oracles, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if mmDb == nil {
|
||||||
|
return oracles, errors.New("no DB connection")
|
||||||
|
}
|
||||||
|
|
||||||
|
oracleQuery := `SELECT m.id, m.title, m.mal_id, COALESCE(SUM(pv.score), 0) AS avgScore FROM movie m
|
||||||
|
JOIN vote pv ON (m.id = pv.movie_id)
|
||||||
|
JOIN promise pp ON (pp.user_id = pv.user_id)
|
||||||
|
JOIN evening me ON (pp.evening_id = me.id)
|
||||||
|
WHERE m.id NOT IN (
|
||||||
|
SELECT m2.id FROM movie m2
|
||||||
|
JOIN evening_movie em2 ON (m2.id = em2.movie_id)
|
||||||
|
JOIN evening e2 ON (em2.evening_id = e2.id)
|
||||||
|
WHERE e2.date < CURDATE()
|
||||||
|
) AND (
|
||||||
|
m.id IN (
|
||||||
|
SELECT mm.movie_source FROM movie m3
|
||||||
|
JOIN movie_movie mm ON (m3.id = mm.movie_target)
|
||||||
|
JOIN evening_movie em3 ON (mm.movie_target = em3.movie_id)
|
||||||
|
JOIN evening e3 ON (em3.evening_id = e3.id)
|
||||||
|
WHERE e3.date < CURDATE() GROUP BY m3.id
|
||||||
|
)
|
||||||
|
OR
|
||||||
|
m.id NOT IN (
|
||||||
|
SELECT mm.movie_source FROM movie m4
|
||||||
|
JOIN movie_movie mm ON (m4.id = mm.movie_source)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
AND pp.promised = 1 AND m.aired = 1 AND me.date >= CURDATE() AND me.date < DATE_ADD(CURDATE(), INTERVAL 1 WEEK) GROUP BY m.id ORDER BY avgScore DESC, m.id ASC;`
|
||||||
|
rows, err := mmDb.Query(oracleQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
oracles = make([]MmOracle, 0)
|
||||||
|
for rows.Next() {
|
||||||
|
var oracle MmOracle
|
||||||
|
var qMalId sql.NullInt64
|
||||||
|
err = rows.Scan(&oracle.Id, &oracle.Title, &qMalId, &oracle.AvgScore)
|
||||||
|
if err != nil {
|
||||||
|
return oracles, err
|
||||||
|
}
|
||||||
|
if qMalId.Valid {
|
||||||
|
oracle.Anime = qMalId.Int64
|
||||||
|
}
|
||||||
|
oracles = append(oracles, oracle)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rows.Err()
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
bytes, err := json.Marshal(oracles)
|
||||||
|
if err == nil {
|
||||||
|
mmCache.Set(key, bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return oracles, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func MmReadCharts() ([]MmOracle, error) {
|
||||||
|
if mmDb == nil {
|
||||||
|
return nil, errors.New("no DB connection")
|
||||||
|
}
|
||||||
|
|
||||||
|
chartsQuery := `SELECT m.id, m.title, m.mal_id FROM movie m
|
||||||
|
JOIN evening_movie em ON em.movie_id = m.id
|
||||||
|
JOIN evening e ON em.evening_id = e.id
|
||||||
|
WHERE e.date <= CURDATE() AND m.mal_id IS NOT NULL;`
|
||||||
|
rows, err := mmDb.Query(chartsQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
charts := make([]MmOracle, 0)
|
||||||
|
for rows.Next() {
|
||||||
|
var chart MmOracle
|
||||||
|
err = rows.Scan(&chart.Id, &chart.Title, &chart.Anime)
|
||||||
|
if err != nil {
|
||||||
|
return charts, err
|
||||||
|
}
|
||||||
|
charts = append(charts, chart)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rows.Err()
|
||||||
|
|
||||||
|
return charts, err
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user