Skip to content

Commit

Permalink
Add O-counter (#334)
Browse files Browse the repository at this point in the history
* Add backend support for o-counter

* Add o-counter buttons everywhere

* Put o-counter button right-aligned on tabs

* Add o-counter filter
  • Loading branch information
WithoutPants authored Feb 3, 2020
1 parent 066295f commit f87117b
Show file tree
Hide file tree
Showing 22 changed files with 325 additions and 9 deletions.
1 change: 1 addition & 0 deletions graphql/documents/data/scene-slim.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ fragment SlimSceneData on Scene {
url
date
rating
o_counter
path

file {
Expand Down
1 change: 1 addition & 0 deletions graphql/documents/data/scene.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ fragment SceneData on Scene {
url
date
rating
o_counter
path

file {
Expand Down
12 changes: 12 additions & 0 deletions graphql/documents/mutations/scene.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ mutation ScenesUpdate($input : [SceneUpdateInput!]!) {
}
}

mutation SceneIncrementO($id: ID!) {
sceneIncrementO(id: $id)
}

mutation SceneDecrementO($id: ID!) {
sceneDecrementO(id: $id)
}

mutation SceneResetO($id: ID!) {
sceneResetO(id: $id)
}

mutation SceneDestroy($id: ID!, $delete_file: Boolean, $delete_generated : Boolean) {
sceneDestroy(input: {id: $id, delete_file: $delete_file, delete_generated: $delete_generated})
}
7 changes: 7 additions & 0 deletions graphql/schema/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ type Mutation {
sceneDestroy(input: SceneDestroyInput!): Boolean!
scenesUpdate(input: [SceneUpdateInput!]!): [Scene]

"""Increments the o-counter for a scene. Returns the new value"""
sceneIncrementO(id: ID!): Int!
"""Decrements the o-counter for a scene. Returns the new value"""
sceneDecrementO(id: ID!): Int!
"""Resets the o-counter for a scene to 0. Returns the new value"""
sceneResetO(id: ID!): Int!

sceneMarkerCreate(input: SceneMarkerCreateInput!): SceneMarker
sceneMarkerUpdate(input: SceneMarkerUpdateInput!): SceneMarker
sceneMarkerDestroy(id: ID!): Boolean!
Expand Down
2 changes: 2 additions & 0 deletions graphql/schema/types/filters.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ input SceneMarkerFilterType {
input SceneFilterType {
"""Filter by rating"""
rating: IntCriterionInput
"""Filter by o-counter"""
o_counter: IntCriterionInput
"""Filter by resolution"""
resolution: ResolutionEnum
"""Filter by duration (in seconds)"""
Expand Down
1 change: 1 addition & 0 deletions graphql/schema/types/scene.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Scene {
url: String
date: String
rating: Int
o_counter: Int
path: String!

file: SceneFileType! # Resolver
Expand Down
60 changes: 60 additions & 0 deletions pkg/api/resolver_mutation_scene.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,3 +422,63 @@ func changeMarker(ctx context.Context, changeType int, changedMarker models.Scen

return sceneMarker, nil
}

func (r *mutationResolver) SceneIncrementO(ctx context.Context, id string) (int, error) {
sceneID, _ := strconv.Atoi(id)

tx := database.DB.MustBeginTx(ctx, nil)
qb := models.NewSceneQueryBuilder()

newVal, err := qb.IncrementOCounter(sceneID, tx)
if err != nil {
_ = tx.Rollback()
return 0, err
}

// Commit
if err := tx.Commit(); err != nil {
return 0, err
}

return newVal, nil
}

func (r *mutationResolver) SceneDecrementO(ctx context.Context, id string) (int, error) {
sceneID, _ := strconv.Atoi(id)

tx := database.DB.MustBeginTx(ctx, nil)
qb := models.NewSceneQueryBuilder()

newVal, err := qb.DecrementOCounter(sceneID, tx)
if err != nil {
_ = tx.Rollback()
return 0, err
}

// Commit
if err := tx.Commit(); err != nil {
return 0, err
}

return newVal, nil
}

func (r *mutationResolver) SceneResetO(ctx context.Context, id string) (int, error) {
sceneID, _ := strconv.Atoi(id)

tx := database.DB.MustBeginTx(ctx, nil)
qb := models.NewSceneQueryBuilder()

newVal, err := qb.ResetOCounter(sceneID, tx)
if err != nil {
_ = tx.Rollback()
return 0, err
}

// Commit
if err := tx.Commit(); err != nil {
return 0, err
}

return newVal, nil
}
2 changes: 1 addition & 1 deletion pkg/database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
)

var DB *sqlx.DB
var appSchemaVersion uint = 2
var appSchemaVersion uint = 3

const sqlite3Driver = "sqlite3_regexp"

Expand Down
1 change: 1 addition & 0 deletions pkg/database/migrations/3_o_counter.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE `scenes` ADD COLUMN `o_counter` tinyint not null default 0;
1 change: 1 addition & 0 deletions pkg/models/model_scene.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type Scene struct {
URL sql.NullString `db:"url" json:"url"`
Date SQLiteDate `db:"date" json:"date"`
Rating sql.NullInt64 `db:"rating" json:"rating"`
OCounter int `db:"o_counter" json:"o_counter"`
Size sql.NullString `db:"size" json:"size"`
Duration sql.NullFloat64 `db:"duration" json:"duration"`
VideoCodec sql.NullString `db:"video_codec" json:"video_codec"`
Expand Down
62 changes: 62 additions & 0 deletions pkg/models/querybuilder_scene.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,60 @@ func (qb *SceneQueryBuilder) Update(updatedScene ScenePartial, tx *sqlx.Tx) (*Sc
return qb.find(updatedScene.ID, tx)
}

func (qb *SceneQueryBuilder) IncrementOCounter(id int, tx *sqlx.Tx) (int, error) {
ensureTx(tx)
_, err := tx.Exec(
`UPDATE scenes SET o_counter = o_counter + 1 WHERE scenes.id = ?`,
id,
)
if err != nil {
return 0, err
}

scene, err := qb.find(id, tx)
if err != nil {
return 0, err
}

return scene.OCounter, nil
}

func (qb *SceneQueryBuilder) DecrementOCounter(id int, tx *sqlx.Tx) (int, error) {
ensureTx(tx)
_, err := tx.Exec(
`UPDATE scenes SET o_counter = o_counter - 1 WHERE scenes.id = ? and scenes.o_counter > 0`,
id,
)
if err != nil {
return 0, err
}

scene, err := qb.find(id, tx)
if err != nil {
return 0, err
}

return scene.OCounter, nil
}

func (qb *SceneQueryBuilder) ResetOCounter(id int, tx *sqlx.Tx) (int, error) {
ensureTx(tx)
_, err := tx.Exec(
`UPDATE scenes SET o_counter = 0 WHERE scenes.id = ?`,
id,
)
if err != nil {
return 0, err
}

scene, err := qb.find(id, tx)
if err != nil {
return 0, err
}

return scene.OCounter, nil
}

func (qb *SceneQueryBuilder) Destroy(id string, tx *sqlx.Tx) error {
return executeDeleteQuery("scenes", id, tx)
}
Expand Down Expand Up @@ -178,6 +232,14 @@ func (qb *SceneQueryBuilder) Query(sceneFilter *SceneFilterType, findFilter *Fin
}
}

if oCounter := sceneFilter.OCounter; oCounter != nil {
clause, count := getIntCriterionWhereClause("scenes.o_counter", *sceneFilter.OCounter)
whereClauses = append(whereClauses, clause)
if count == 1 {
args = append(args, sceneFilter.OCounter.Value)
}
}

if durationFilter := sceneFilter.Duration; durationFilter != nil {
clause, thisArgs := getDurationWhereClause(*durationFilter)
whereClauses = append(whereClauses, clause)
Expand Down
2 changes: 1 addition & 1 deletion pkg/models/querybuilder_sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func getSort(sort string, direction string, tableName string) string {

const randomSeedPrefix = "random_"

if strings.Contains(sort, "_count") {
if strings.HasSuffix(sort, "_count") {
var relationTableName = strings.Split(sort, "_")[0] // TODO: pluralize?
colName := getColumn(relationTableName, "id")
return " ORDER BY COUNT(distinct " + colName + ") " + direction
Expand Down
50 changes: 50 additions & 0 deletions ui/v2/src/components/scenes/OCounterButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, { FunctionComponent } from "react";
import { Button, Popover, Menu, MenuItem } from "@blueprintjs/core";
import { Icons } from "../../utils/icons";

export interface IOCounterButtonProps {
loading: boolean
value: number
onIncrement: () => void
onDecrement: () => void
onReset: () => void
onMenuOpened?: () => void
onMenuClosed?: () => void
}

export const OCounterButton: FunctionComponent<IOCounterButtonProps> = (props: IOCounterButtonProps) => {
function renderButton() {
return (
<Button
loading={props.loading}
icon={Icons.sweatDrops()}
text={props.value}
minimal={true}
onClick={props.onIncrement}
disabled={props.loading}
/>
);
}

if (props.value) {
// just render the button by itself
return (
<Popover
interactionKind={"hover"}
hoverOpenDelay={1000}
position="bottom"
disabled={props.loading}
onOpening={props.onMenuOpened}
onClosing={props.onMenuClosed}
>
{renderButton()}
<Menu>
<MenuItem text="Decrement" icon="minus" onClick={props.onDecrement}/>
<MenuItem text="Reset" icon="disable" onClick={props.onReset}/>
</Menu>
</Popover>
);
} else {
return renderButton();
}
}
16 changes: 15 additions & 1 deletion ui/v2/src/components/scenes/SceneCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { TextUtils } from "../../utils/text";
import { TagLink } from "../Shared/TagLink";
import { ZoomUtils } from "../../utils/zoom";
import { StashService } from "../../core/StashService";
import { Icons } from "../../utils/icons";

interface ISceneCardProps {
scene: GQL.SlimSceneDataFragment;
Expand Down Expand Up @@ -142,17 +143,30 @@ export const SceneCard: FunctionComponent<ISceneCardProps> = (props: ISceneCardP
);
}

function maybeRenderOCounter() {
if (props.scene.o_counter) {
return (
<Button
icon={Icons.sweatDrops()}
text={props.scene.o_counter}
/>
)
}
}

function maybeRenderPopoverButtonGroup() {
if (props.scene.tags.length > 0 ||
props.scene.performers.length > 0 ||
props.scene.scene_markers.length > 0) {
props.scene.scene_markers.length > 0 ||
props.scene.o_counter) {
return (
<>
<Divider />
<ButtonGroup minimal={true} className="card-section centered">
{maybeRenderTagPopoverButton()}
{maybeRenderPerformerPopoverButton()}
{maybeRenderSceneMarkerPopoverButton()}
{maybeRenderOCounter()}
</ButtonGroup>
</>
);
Expand Down
Loading

0 comments on commit f87117b

Please sign in to comment.