Add additional stats to the Stats page (#3812)

* Add o_counter, play_duration, play_count, unique_play_count stats
This commit is contained in:
hontheinternet 2023-07-11 13:32:42 +09:00 committed by GitHub
parent 4f0e0e1d99
commit ff22577ce0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 209 additions and 21 deletions

2
.gitignore vendored
View file

@ -63,4 +63,4 @@ node_modules
/stash
dist
.DS_Store
/.local
/.local*

View file

@ -40,16 +40,20 @@ query AllTagsForFilter {
query Stats {
stats {
scene_count,
scenes_size,
scenes_duration,
image_count,
images_size,
gallery_count,
performer_count,
studio_count,
movie_count,
scene_count
scenes_size
scenes_duration
image_count
images_size
gallery_count
performer_count
studio_count
movie_count
tag_count
total_o_count
total_play_duration
total_play_count
scenes_played
}
}

View file

@ -9,4 +9,8 @@ type StatsResultType {
studio_count: Int!
movie_count: Int!
tag_count: Int!
total_o_count: Int!
total_play_duration: Float!
total_play_count: Int!
scenes_played: Int!
}

View file

@ -157,6 +157,10 @@ func (r *queryResolver) Stats(ctx context.Context) (*StatsResultType, error) {
studiosCount, _ := studiosQB.Count(ctx)
moviesCount, _ := moviesQB.Count(ctx)
tagsCount, _ := tagsQB.Count(ctx)
totalOCount, _ := scenesQB.OCount(ctx)
totalPlayDuration, _ := scenesQB.PlayDuration(ctx)
totalPlayCount, _ := scenesQB.PlayCount(ctx)
uniqueScenePlayCount, _ := scenesQB.UniqueScenePlayCount(ctx)
ret = StatsResultType{
SceneCount: scenesCount,
@ -169,6 +173,10 @@ func (r *queryResolver) Stats(ctx context.Context) (*StatsResultType, error) {
StudioCount: studiosCount,
MovieCount: moviesCount,
TagCount: tagsCount,
TotalOCount: totalOCount,
TotalPlayDuration: totalPlayDuration,
TotalPlayCount: totalPlayCount,
ScenesPlayed: uniqueScenePlayCount,
}
return nil

View file

@ -687,6 +687,27 @@ func (_m *SceneReaderWriter) IncrementWatchCount(ctx context.Context, id int) (i
return r0, r1
}
// OCount provides a mock function with given fields: ctx
func (_m *SceneReaderWriter) OCount(ctx context.Context) (int, error) {
ret := _m.Called(ctx)
var r0 int
if rf, ok := ret.Get(0).(func(context.Context) int); ok {
r0 = rf(ctx)
} else {
r0 = ret.Get(0).(int)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// OCountByPerformerID provides a mock function with given fields: ctx, performerID
func (_m *SceneReaderWriter) OCountByPerformerID(ctx context.Context, performerID int) (int, error) {
ret := _m.Called(ctx, performerID)
@ -708,6 +729,48 @@ func (_m *SceneReaderWriter) OCountByPerformerID(ctx context.Context, performerI
return r0, r1
}
// PlayCount provides a mock function with given fields: ctx
func (_m *SceneReaderWriter) PlayCount(ctx context.Context) (int, error) {
ret := _m.Called(ctx)
var r0 int
if rf, ok := ret.Get(0).(func(context.Context) int); ok {
r0 = rf(ctx)
} else {
r0 = ret.Get(0).(int)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// PlayDuration provides a mock function with given fields: ctx
func (_m *SceneReaderWriter) PlayDuration(ctx context.Context) (float64, error) {
ret := _m.Called(ctx)
var r0 float64
if rf, ok := ret.Get(0).(func(context.Context) float64); ok {
r0 = rf(ctx)
} else {
r0 = ret.Get(0).(float64)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Query provides a mock function with given fields: ctx, options
func (_m *SceneReaderWriter) Query(ctx context.Context, options models.SceneQueryOptions) (*models.SceneQueryResult, error) {
ret := _m.Called(ctx, options)
@ -815,6 +878,27 @@ func (_m *SceneReaderWriter) Size(ctx context.Context) (float64, error) {
return r0, r1
}
// UniqueScenePlayCount provides a mock function with given fields: ctx
func (_m *SceneReaderWriter) UniqueScenePlayCount(ctx context.Context) (int, error) {
ret := _m.Called(ctx)
var r0 int
if rf, ok := ret.Get(0).(func(context.Context) int); ok {
r0 = rf(ctx)
} else {
r0 = ret.Get(0).(int)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Update provides a mock function with given fields: ctx, updatedScene
func (_m *SceneReaderWriter) Update(ctx context.Context, updatedScene *models.Scene) error {
ret := _m.Called(ctx, updatedScene)

View file

@ -168,12 +168,16 @@ type SceneReader interface {
CountByPerformerID(ctx context.Context, performerID int) (int, error)
OCountByPerformerID(ctx context.Context, performerID int) (int, error)
OCount(ctx context.Context) (int, error)
// FindByStudioID(studioID int) ([]*Scene, error)
FindByMovieID(ctx context.Context, movieID int) ([]*Scene, error)
CountByMovieID(ctx context.Context, movieID int) (int, error)
Count(ctx context.Context) (int, error)
PlayCount(ctx context.Context) (int, error)
UniqueScenePlayCount(ctx context.Context) (int, error)
Size(ctx context.Context) (float64, error)
Duration(ctx context.Context) (float64, error)
PlayDuration(ctx context.Context) (float64, error)
// SizeCount() (string, error)
CountByStudioID(ctx context.Context, studioID int) (int, error)
CountByTagID(ctx context.Context, tagID int) (int, error)

View file

@ -705,6 +705,18 @@ func (qb *SceneStore) OCountByPerformerID(ctx context.Context, performerID int)
return ret, nil
}
func (qb *SceneStore) OCount(ctx context.Context) (int, error) {
table := qb.table()
q := dialect.Select(goqu.COALESCE(goqu.SUM("o_counter"), 0)).From(table)
var ret int
if err := querySimple(ctx, q, &ret); err != nil {
return 0, err
}
return ret, nil
}
func (qb *SceneStore) FindByMovieID(ctx context.Context, movieID int) ([]*models.Scene, error) {
sq := dialect.From(scenesMoviesJoinTable).Select(scenesMoviesJoinTable.Col(sceneIDColumn)).Where(
scenesMoviesJoinTable.Col(movieIDColumn).Eq(movieID),
@ -730,6 +742,24 @@ func (qb *SceneStore) Count(ctx context.Context) (int, error) {
return count(ctx, q)
}
func (qb *SceneStore) PlayCount(ctx context.Context) (int, error) {
q := dialect.Select(goqu.COALESCE(goqu.SUM("play_count"), 0)).From(qb.table())
var ret int
if err := querySimple(ctx, q, &ret); err != nil {
return 0, err
}
return ret, nil
}
func (qb *SceneStore) UniqueScenePlayCount(ctx context.Context) (int, error) {
table := qb.table()
q := dialect.Select(goqu.COUNT("*")).From(table).Where(table.Col("play_count").Gt(0))
return count(ctx, q)
}
func (qb *SceneStore) Size(ctx context.Context) (float64, error) {
table := qb.table()
fileTable := fileTableMgr.table
@ -771,6 +801,19 @@ func (qb *SceneStore) Duration(ctx context.Context) (float64, error) {
return ret, nil
}
func (qb *SceneStore) PlayDuration(ctx context.Context) (float64, error) {
table := qb.table()
q := dialect.Select(goqu.COALESCE(goqu.SUM("play_duration"), 0)).From(table)
var ret float64
if err := querySimple(ctx, q, &ret); err != nil {
return 0, err
}
return ret, nil
}
func (qb *SceneStore) CountByStudioID(ctx context.Context, studioID int) (int, error) {
table := qb.table()

View file

@ -18,6 +18,11 @@ export const Stats: React.FC = () => {
3
);
const totalPlayDuration = TextUtils.secondsAsTimeString(
data.stats.total_play_duration,
3
);
return (
<div className="mt-5">
<div className="col col-sm-8 m-sm-auto row stats">
@ -114,6 +119,38 @@ export const Stats: React.FC = () => {
</p>
</div>
</div>
<div className="col col-sm-8 m-sm-auto row stats">
<div className="stats-element">
<p className="title">
<FormattedNumber value={data.stats.total_o_count} />
</p>
<p className="heading">
<FormattedMessage id="stats.total_o_count" />
</p>
</div>
<div className="stats-element">
<p className="title">
<FormattedNumber value={data.stats.total_play_count} />
</p>
<p className="heading">
<FormattedMessage id="stats.total_play_count" />
</p>
</div>
<div className="stats-element">
<p className="title">
<FormattedNumber value={data.stats.scenes_played} />
</p>
<p className="heading">
<FormattedMessage id="stats.scenes_played" />
</p>
</div>
<div className="stats-element">
<p className="title">{totalPlayDuration || "-"}</p>
<p className="heading">
<FormattedMessage id="stats.total_play_duration" />
</p>
</div>
</div>
</div>
);
};

View file

@ -1218,7 +1218,11 @@
"stats": {
"image_size": "Images size",
"scenes_duration": "Scenes duration",
"scenes_size": "Scenes size"
"scenes_size": "Scenes size",
"scenes_played": "Scenes Played",
"total_play_duration": "Total Play Duration",
"total_play_count": "Total Play Count",
"total_o_count": "Total O-Count"
},
"status": "Status: {statusText}",
"studio": "Studio",