Compare commits

...

2 Commits

Author SHA1 Message Date
daru
cc525f2460 Charts V2 2022-06-30 00:21:38 +02:00
daru
da474ecede Charts V1 2022-06-29 22:40:46 +02:00
10 changed files with 284 additions and 100 deletions

2
go.mod
View File

@@ -16,7 +16,7 @@ require (
require (
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/bwmarrin/snowflake v0.3.0 // indirect
github.com/klauspost/compress v1.15.6 // indirect
github.com/klauspost/compress v1.15.7 // 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

4
go.sum
View File

@@ -20,8 +20,8 @@ github.com/gookit/color v1.5.1/go.mod h1:wZFzea4X8qN6vHOSP2apMb4/+w/orMznEzYsIHP
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.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.6 h1:6D9PcO8QWu0JyaQ2zUMmu16T1T+zjjEpP91guRsvDfY=
github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/compress v1.15.7 h1:7cgTQxJCU/vy+oP/E3B9RGbQTgbiVzIJWIKOLoAsPok=
github.com/klauspost/compress v1.15.7/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=

View File

@@ -19,7 +19,7 @@ import (
)
const (
husoVersion = "1.2"
husoVersion = "1.3"
registerSecret = "綾波レイ"
seasonApiJikan = "seasons/now"
seasonStrJikan = "seasons/"

View File

@@ -317,3 +317,10 @@ type MmOracle struct {
Anime int64 `json:"anime"`
AvgScore int `json:"avgScore"`
}
type MovieChart struct {
MmId int `json:"mmId"`
AvgScore float64 `json:"avgScore"`
UserCount int `json:"userCount"`
Data Anime `json:"data"`
}

13
ober.go
View File

@@ -9,6 +9,7 @@ import (
"time"
"github.com/fasthttp/router"
"github.com/gookit/color"
"github.com/valyala/fasthttp"
"github.com/xujiajun/nutsdb"
)
@@ -46,11 +47,15 @@ func Start(ctx *fasthttp.RequestCtx) {
oracles, err := MmReadOracle()
if err != nil {
addErrorToCtx(ctx, err)
return
color.Errorln(err.Error())
}
WriteIndex(ctx, season, oracles, logOut.String())
charts, err := BuildMovieCharts()
if err != nil {
color.Errorln(err.Error())
}
WriteIndex(ctx, season, oracles, charts, logOut.String())
ctx.SetContentType("text/html; charset=utf-8")
ctx.SetStatusCode(fasthttp.StatusOK)
@@ -619,7 +624,7 @@ func processUpdateReq(ctx *fasthttp.RequestCtx, update bool) {
if update {
// anime exitsts => save
// 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
if listState == malApiStatusC {
ctx.WriteString("Du hast schon fertig geschaut bro")

View File

@@ -59,7 +59,7 @@ func Arbeit() {
for _, a := range animesUsers {
// iterate 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 {
color.Errorln(err.Error())
logOut.WriteError(err)
@@ -67,8 +67,8 @@ func Arbeit() {
}
// check if user set anime as completed
if listState == malApiStatusC {
color.Infof("%s finished %d\n", u.Username, a.Anime)
logOut.WriteLine(fmt.Sprintf("📜 %s finished %d !", u.Username, a.Anime))
color.Infof("%s finished %d scored %d\n", u.Username, a.Anime, score)
logOut.WriteLine(fmt.Sprintf("📜 %s finished %d scored %d !", u.Username, a.Anime, score))
// delete user from anime
_, err = DeleteUserFromAnime(u.Username, u.MalID, a.Anime)
if err != nil {
@@ -194,6 +194,27 @@ func LangeArbeit() {
}
}
charts, err := BuildMovieCharts()
if err != nil {
color.Errorln(err.Error())
logOut.WriteError(err)
} else {
for _, c := range charts {
// search season first
_, err = SearchSeason(c.Data.Anime)
if err == nil {
continue
}
err = refreshAnime(c.Data.Anime)
if err != nil {
color.Errorln(err.Error())
logOut.WriteError(err)
continue
}
count++
}
}
color.Infof("%d Anime aktualisiert\n", count)
logOut.WriteLine(fmt.Sprintf("🔃 %d Anime aktualisiert", count))
}

View File

@@ -4,9 +4,11 @@ import (
"encoding/json"
"errors"
"fmt"
"sort"
"strings"
"time"
"github.com/gookit/color"
"github.com/xujiajun/nutsdb"
)
@@ -180,57 +182,56 @@ func SearchAppointments(animeId int64) ([]Appointment, error) {
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
newProgress, updated, err := fetchProgressOnState(animeId, userId, progress, username, malApiStatusW)
newProgress, updated, score, err := FetchProgressOnState(animeId, username, malApiStatusW)
if err != nil {
return newProgress, updated, "", err
return newProgress, updated, score, "", err
}
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)
newProgress, updated, score, err = FetchProgressOnState(animeId, username, malApiStatusH)
if err != nil {
return newProgress, updated, "", err
return newProgress, updated, score, "", err
}
if newProgress != -1 {
return newProgress, updated, malApiStatusH, err
return newProgress, updated, score, malApiStatusH, err
}
// check completed
newProgress, updated, err = fetchProgressOnState(animeId, userId, progress, username, malApiStatusC)
newProgress, updated, score, err = FetchProgressOnState(animeId, username, malApiStatusC)
if err != nil {
return newProgress, updated, "", err
return newProgress, updated, score, "", err
}
if newProgress != -1 {
return newProgress, updated, malApiStatusC, err
return newProgress, updated, score, malApiStatusC, err
}
// check dropped
newProgress, updated, err = fetchProgressOnState(animeId, userId, progress, username, malApiStatusD)
newProgress, updated, score, err = FetchProgressOnState(animeId, username, malApiStatusD)
if err != nil {
return newProgress, updated, "", err
return newProgress, updated, score, "", err
}
if newProgress != -1 {
return newProgress, updated, malApiStatusD, err
return newProgress, updated, score, malApiStatusD, err
}
// 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)
if err != nil {
return 0, time.Time{}, err
return 0, time.Time{}, 0, err
}
for _, a := range list.Data {
// check if found
if a.Node.ID == animeId {
// check if progress changed
return a.ListStatus.NumEpisodesWatched, a.ListStatus.UpdatedAt, nil
return a.ListStatus.NumEpisodesWatched, a.ListStatus.UpdatedAt, a.ListStatus.Score, nil
}
}
// no progess found
return -1, time.Now(), nil
return -1, time.Now(), 0, nil
}
func AddToChat(old, new, user string) string {
@@ -270,3 +271,66 @@ func CheckAnimeExistInDbAndUserWatches(animeId, userId int64) (bool, error) {
}
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, err := SearchAnime(m.Anime)
if err != nil {
color.Errorln(err.Error())
continue
}
c.Data = *anime
scoreSum := 0
for _, u := range users {
progress, _, score, err := FetchProgressOnState(anime.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
}

View File

@@ -1,5 +1,5 @@
{% package main %}
{% func Index(animes []Anime, oracles []MmOracle, log string) %}
{% func Index(animes []Anime, oracles []MmOracle, charts []MovieChart, log string) %}
{% collapsespace %}
<!DOCTYPE html>
<html lang="en">
@@ -30,23 +30,52 @@ body { background-color: #1a1a1a; color: #fff; }
</table>
</br>
<table>
<tr>
<th>MALID</th>
<th>SCORE</th>
<th>TITLE</th>
</tr>
{% for _, anime := range animes %}
<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>{%d anime.Episodes %}</td>
<td>{%f anime.Score %}</td>
</tr>
{% endfor %}
</table>
<h2>MovieManager Charts</h2>
<table>
<tr>
<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="{%s chart.Data.URL %}" target="_blank" rel="noopener noreferrer">{%dl chart.Data.Anime %}</a></td>
<td>{%d chart.UserCount %}</td>
<td><strong>{%f.2 chart.AvgScore %}</strong></td>
<td><strong>{%s chart.Data.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>
<td>{%dl oracle.Anime %}</td>
</tr>
{% endfor %}
</table>

View File

@@ -18,7 +18,7 @@ var (
)
//line season.qtpl:2
func StreamIndex(qw422016 *qt422016.Writer, animes []Anime, oracles []MmOracle, log string) {
func StreamIndex(qw422016 *qt422016.Writer, animes []Anime, oracles []MmOracle, charts []MovieChart, log string) {
//line season.qtpl:2
qw422016.N().S(`
`)
@@ -31,91 +31,123 @@ func StreamIndex(qw422016 *qt422016.Writer, animes []Anime, oracles []MmOracle,
//line season.qtpl:28
qw422016.N().D(len(animes))
//line season.qtpl:28
qw422016.N().S(`</td> </tr> </table> </br> <table> `)
//line season.qtpl:33
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:33
//line season.qtpl:38
qw422016.N().S(` <tr> <td><a href="`)
//line season.qtpl:35
//line season.qtpl:40
qw422016.E().S(anime.URL)
//line season.qtpl:35
//line season.qtpl:40
qw422016.N().S(`" target="_blank" rel="noopener noreferrer">`)
//line season.qtpl:35
//line season.qtpl:40
qw422016.N().DL(anime.Anime)
//line season.qtpl:35
qw422016.N().S(`</a></td> <td><strong>`)
//line season.qtpl:36
qw422016.E().S(anime.Title)
//line season.qtpl:36
qw422016.N().S(`</strong></td> <td>`)
//line season.qtpl:37
qw422016.N().D(anime.Episodes)
//line season.qtpl:37
qw422016.N().S(`</td> <td>`)
//line season.qtpl:38
qw422016.N().F(anime.Score)
//line season.qtpl:38
qw422016.N().S(`</td> </tr> `)
//line season.qtpl:40
}
//line season.qtpl:40
qw422016.N().S(` </table> <h2>MovieManager Oracle</h2> <table> `)
//line season.qtpl:44
for _, oracle := range oracles {
//line season.qtpl:44
qw422016.N().S(` <tr> <td><a href="https://movies.hanami.family/movie/`)
//line season.qtpl:46
qw422016.N().D(oracle.Id)
//line season.qtpl:46
qw422016.N().S(`" target="_blank" rel="noopener noreferrer">`)
//line season.qtpl:46
qw422016.N().D(oracle.Id)
//line season.qtpl:46
qw422016.N().S(`</a></td> <td>`)
//line season.qtpl:47
qw422016.N().D(oracle.AvgScore)
//line season.qtpl:47
//line season.qtpl:41
qw422016.N().FPrec(anime.Score, 2)
//line season.qtpl:41
qw422016.N().S(`</td> <td><strong>`)
//line season.qtpl:48
qw422016.E().S(oracle.Title)
//line season.qtpl:48
qw422016.N().S(`</strong></td> <td>`)
//line season.qtpl:49
qw422016.N().DL(oracle.Anime)
//line season.qtpl:49
qw422016.N().S(`</td> </tr> `)
//line season.qtpl:51
//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:51
qw422016.N().S(` </table> </body> </html> `)
//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="`)
//line season.qtpl:58
qw422016.E().S(chart.Data.URL)
//line season.qtpl:58
qw422016.N().S(`" target="_blank" rel="noopener noreferrer">`)
//line season.qtpl:58
qw422016.N().DL(chart.Data.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.Data.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(`
`)
//line season.qtpl:56
//line season.qtpl:85
}
//line season.qtpl:56
func WriteIndex(qq422016 qtio422016.Writer, animes []Anime, oracles []MmOracle, log string) {
//line season.qtpl:56
//line season.qtpl:85
func WriteIndex(qq422016 qtio422016.Writer, animes []Anime, oracles []MmOracle, charts []MovieChart, log string) {
//line season.qtpl:85
qw422016 := qt422016.AcquireWriter(qq422016)
//line season.qtpl:56
StreamIndex(qw422016, animes, oracles, log)
//line season.qtpl:56
//line season.qtpl:85
StreamIndex(qw422016, animes, oracles, charts, log)
//line season.qtpl:85
qt422016.ReleaseWriter(qw422016)
//line season.qtpl:56
//line season.qtpl:85
}
//line season.qtpl:56
func Index(animes []Anime, oracles []MmOracle, log string) string {
//line season.qtpl:56
//line season.qtpl:85
func Index(animes []Anime, oracles []MmOracle, charts []MovieChart, log string) string {
//line season.qtpl:85
qb422016 := qt422016.AcquireByteBuffer()
//line season.qtpl:56
WriteIndex(qb422016, animes, oracles, log)
//line season.qtpl:56
//line season.qtpl:85
WriteIndex(qb422016, animes, oracles, charts, log)
//line season.qtpl:85
qs422016 := string(qb422016.B)
//line season.qtpl:56
//line season.qtpl:85
qt422016.ReleaseByteBuffer(qb422016)
//line season.qtpl:56
//line season.qtpl:85
return qs422016
//line season.qtpl:56
//line season.qtpl:85
}

View File

@@ -85,3 +85,29 @@ func MmReadOracle() ([]MmOracle, error) {
return oracles, err
}
func MmReadCharts() ([]MmOracle, error) {
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
}