mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 12:24:38 +03:00
Add movie count to performer and studio card (#1760)
* Add movies and movie_count properties to Performer type Extend the GraphQL API to allow getting the movies and movie count by performer. * Add movies count to performer card * Add movies and movie_count properties to Studio type Extend the GraphQL API to allow getting the movies and movie count by studio. * Add movies count to studio card
This commit is contained in:
@@ -22,6 +22,7 @@ fragment PerformerData on Performer {
|
|||||||
scene_count
|
scene_count
|
||||||
image_count
|
image_count
|
||||||
gallery_count
|
gallery_count
|
||||||
|
movie_count
|
||||||
|
|
||||||
tags {
|
tags {
|
||||||
...SlimTagData
|
...SlimTagData
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ fragment StudioData on Studio {
|
|||||||
scene_count
|
scene_count
|
||||||
image_count
|
image_count
|
||||||
gallery_count
|
gallery_count
|
||||||
|
movie_count
|
||||||
stash_ids {
|
stash_ids {
|
||||||
stash_id
|
stash_id
|
||||||
endpoint
|
endpoint
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ type Performer {
|
|||||||
weight: Int
|
weight: Int
|
||||||
created_at: Time!
|
created_at: Time!
|
||||||
updated_at: Time!
|
updated_at: Time!
|
||||||
|
movie_count: Int
|
||||||
|
movies: [Movie!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
input PerformerCreateInput {
|
input PerformerCreateInput {
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ type Studio {
|
|||||||
details: String
|
details: String
|
||||||
created_at: Time!
|
created_at: Time!
|
||||||
updated_at: Time!
|
updated_at: Time!
|
||||||
|
movie_count: Int
|
||||||
|
movies: [Movie!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
input StudioCreateInput {
|
input StudioCreateInput {
|
||||||
|
|||||||
@@ -254,3 +254,26 @@ func (r *performerResolver) CreatedAt(ctx context.Context, obj *models.Performer
|
|||||||
func (r *performerResolver) UpdatedAt(ctx context.Context, obj *models.Performer) (*time.Time, error) {
|
func (r *performerResolver) UpdatedAt(ctx context.Context, obj *models.Performer) (*time.Time, error) {
|
||||||
return &obj.UpdatedAt.Timestamp, nil
|
return &obj.UpdatedAt.Timestamp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *performerResolver) Movies(ctx context.Context, obj *models.Performer) (ret []*models.Movie, err error) {
|
||||||
|
if err := r.withReadTxn(ctx, func(repo models.ReaderRepository) error {
|
||||||
|
ret, err = repo.Movie().FindByPerformerID(obj.ID)
|
||||||
|
return err
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *performerResolver) MovieCount(ctx context.Context, obj *models.Performer) (ret *int, err error) {
|
||||||
|
var res int
|
||||||
|
if err := r.withReadTxn(ctx, func(repo models.ReaderRepository) error {
|
||||||
|
res, err = repo.Movie().CountByPerformerID(obj.ID)
|
||||||
|
return err
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &res, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -151,3 +151,26 @@ func (r *studioResolver) CreatedAt(ctx context.Context, obj *models.Studio) (*ti
|
|||||||
func (r *studioResolver) UpdatedAt(ctx context.Context, obj *models.Studio) (*time.Time, error) {
|
func (r *studioResolver) UpdatedAt(ctx context.Context, obj *models.Studio) (*time.Time, error) {
|
||||||
return &obj.UpdatedAt.Timestamp, nil
|
return &obj.UpdatedAt.Timestamp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *studioResolver) Movies(ctx context.Context, obj *models.Studio) (ret []*models.Movie, err error) {
|
||||||
|
if err := r.withReadTxn(ctx, func(repo models.ReaderRepository) error {
|
||||||
|
ret, err = repo.Movie().FindByStudioID(obj.ID)
|
||||||
|
return err
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *studioResolver) MovieCount(ctx context.Context, obj *models.Studio) (ret *int, err error) {
|
||||||
|
var res int
|
||||||
|
if err := r.withReadTxn(ctx, func(repo models.ReaderRepository) error {
|
||||||
|
res, err = repo.Movie().CountByStudioID(obj.ID)
|
||||||
|
return err
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &res, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -56,6 +56,48 @@ func (_m *MovieReaderWriter) Count() (int, error) {
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CountByPerformerID provides a mock function with given fields: performerID
|
||||||
|
func (_m *MovieReaderWriter) CountByPerformerID(performerID int) (int, error) {
|
||||||
|
ret := _m.Called(performerID)
|
||||||
|
|
||||||
|
var r0 int
|
||||||
|
if rf, ok := ret.Get(0).(func(int) int); ok {
|
||||||
|
r0 = rf(performerID)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Get(0).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(int) error); ok {
|
||||||
|
r1 = rf(performerID)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountByStudioID provides a mock function with given fields: studioID
|
||||||
|
func (_m *MovieReaderWriter) CountByStudioID(studioID int) (int, error) {
|
||||||
|
ret := _m.Called(studioID)
|
||||||
|
|
||||||
|
var r0 int
|
||||||
|
if rf, ok := ret.Get(0).(func(int) int); ok {
|
||||||
|
r0 = rf(studioID)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Get(0).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(int) error); ok {
|
||||||
|
r1 = rf(studioID)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// Create provides a mock function with given fields: newMovie
|
// Create provides a mock function with given fields: newMovie
|
||||||
func (_m *MovieReaderWriter) Create(newMovie models.Movie) (*models.Movie, error) {
|
func (_m *MovieReaderWriter) Create(newMovie models.Movie) (*models.Movie, error) {
|
||||||
ret := _m.Called(newMovie)
|
ret := _m.Called(newMovie)
|
||||||
@@ -176,6 +218,52 @@ func (_m *MovieReaderWriter) FindByNames(names []string, nocase bool) ([]*models
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindByPerformerID provides a mock function with given fields: performerID
|
||||||
|
func (_m *MovieReaderWriter) FindByPerformerID(performerID int) ([]*models.Movie, error) {
|
||||||
|
ret := _m.Called(performerID)
|
||||||
|
|
||||||
|
var r0 []*models.Movie
|
||||||
|
if rf, ok := ret.Get(0).(func(int) []*models.Movie); ok {
|
||||||
|
r0 = rf(performerID)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*models.Movie)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(int) error); ok {
|
||||||
|
r1 = rf(performerID)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindByStudioID provides a mock function with given fields: studioID
|
||||||
|
func (_m *MovieReaderWriter) FindByStudioID(studioID int) ([]*models.Movie, error) {
|
||||||
|
ret := _m.Called(studioID)
|
||||||
|
|
||||||
|
var r0 []*models.Movie
|
||||||
|
if rf, ok := ret.Get(0).(func(int) []*models.Movie); ok {
|
||||||
|
r0 = rf(studioID)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*models.Movie)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(int) error); ok {
|
||||||
|
r1 = rf(studioID)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// FindMany provides a mock function with given fields: ids
|
// FindMany provides a mock function with given fields: ids
|
||||||
func (_m *MovieReaderWriter) FindMany(ids []int) ([]*models.Movie, error) {
|
func (_m *MovieReaderWriter) FindMany(ids []int) ([]*models.Movie, error) {
|
||||||
ret := _m.Called(ids)
|
ret := _m.Called(ids)
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ type MovieReader interface {
|
|||||||
Query(movieFilter *MovieFilterType, findFilter *FindFilterType) ([]*Movie, int, error)
|
Query(movieFilter *MovieFilterType, findFilter *FindFilterType) ([]*Movie, int, error)
|
||||||
GetFrontImage(movieID int) ([]byte, error)
|
GetFrontImage(movieID int) ([]byte, error)
|
||||||
GetBackImage(movieID int) ([]byte, error)
|
GetBackImage(movieID int) ([]byte, error)
|
||||||
|
FindByPerformerID(performerID int) ([]*Movie, error)
|
||||||
|
CountByPerformerID(performerID int) (int, error)
|
||||||
|
FindByStudioID(studioID int) ([]*Movie, error)
|
||||||
|
CountByStudioID(studioID int) (int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type MovieWriter interface {
|
type MovieWriter interface {
|
||||||
|
|||||||
@@ -308,3 +308,42 @@ func (qb *movieQueryBuilder) GetBackImage(movieID int) ([]byte, error) {
|
|||||||
query := `SELECT back_image from movies_images WHERE movie_id = ?`
|
query := `SELECT back_image from movies_images WHERE movie_id = ?`
|
||||||
return getImage(qb.tx, query, movieID)
|
return getImage(qb.tx, query, movieID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (qb *movieQueryBuilder) FindByPerformerID(performerID int) ([]*models.Movie, error) {
|
||||||
|
query := `SELECT DISTINCT movies.*
|
||||||
|
FROM movies
|
||||||
|
INNER JOIN movies_scenes ON movies.id = movies_scenes.movie_id
|
||||||
|
INNER JOIN performers_scenes ON performers_scenes.scene_id = movies_scenes.scene_id
|
||||||
|
WHERE performers_scenes.performer_id = ?
|
||||||
|
`
|
||||||
|
args := []interface{}{performerID}
|
||||||
|
return qb.queryMovies(query, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *movieQueryBuilder) CountByPerformerID(performerID int) (int, error) {
|
||||||
|
query := `SELECT COUNT(DISTINCT movies_scenes.movie_id) AS count
|
||||||
|
FROM movies_scenes
|
||||||
|
INNER JOIN performers_scenes ON performers_scenes.scene_id = movies_scenes.scene_id
|
||||||
|
WHERE performers_scenes.performer_id = ?
|
||||||
|
`
|
||||||
|
args := []interface{}{performerID}
|
||||||
|
return qb.runCountQuery(query, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *movieQueryBuilder) FindByStudioID(studioID int) ([]*models.Movie, error) {
|
||||||
|
query := `SELECT movies.*
|
||||||
|
FROM movies
|
||||||
|
WHERE movies.studio_id = ?
|
||||||
|
`
|
||||||
|
args := []interface{}{studioID}
|
||||||
|
return qb.queryMovies(query, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *movieQueryBuilder) CountByStudioID(studioID int) (int, error) {
|
||||||
|
query := `SELECT COUNT(1) AS count
|
||||||
|
FROM movies
|
||||||
|
WHERE movies.studio_id = ?
|
||||||
|
`
|
||||||
|
args := []interface{}{studioID}
|
||||||
|
return qb.runCountQuery(query, args)
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
* Support filtering Movies by Performers. ([#1675](https://github.com/stashapp/stash/pull/1675))
|
* Support filtering Movies by Performers. ([#1675](https://github.com/stashapp/stash/pull/1675))
|
||||||
|
|
||||||
### 🎨 Improvements
|
### 🎨 Improvements
|
||||||
|
* Added movie count to performer and studio cards. ([#1760](https://github.com/stashapp/stash/pull/1760))
|
||||||
* Added date and details to Movie card, and move scene count to icon. ([#1758](https://github.com/stashapp/stash/pull/1758))
|
* Added date and details to Movie card, and move scene count to icon. ([#1758](https://github.com/stashapp/stash/pull/1758))
|
||||||
* Added date and details to Gallery card, and move image count to icon. ([#1763](https://github.com/stashapp/stash/pull/1763))
|
* Added date and details to Gallery card, and move image count to icon. ([#1763](https://github.com/stashapp/stash/pull/1763))
|
||||||
* Optimised image thumbnail generation (optionally using `libvips`) and made optional. ([#1655](https://github.com/stashapp/stash/pull/1655))
|
* Optimised image thumbnail generation (optionally using `libvips`) and made optional. ([#1655](https://github.com/stashapp/stash/pull/1655))
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export interface IPerformerCardExtraCriteria {
|
|||||||
scenes: Criterion<CriterionValue>[];
|
scenes: Criterion<CriterionValue>[];
|
||||||
images: Criterion<CriterionValue>[];
|
images: Criterion<CriterionValue>[];
|
||||||
galleries: Criterion<CriterionValue>[];
|
galleries: Criterion<CriterionValue>[];
|
||||||
|
movies: Criterion<CriterionValue>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IPerformerCardProps {
|
interface IPerformerCardProps {
|
||||||
@@ -124,18 +125,32 @@ export const PerformerCard: React.FC<IPerformerCardProps> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function maybeRenderMoviesPopoverButton() {
|
||||||
|
if (!performer.movie_count) return;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PopoverCountButton
|
||||||
|
type="movie"
|
||||||
|
count={performer.movie_count}
|
||||||
|
url={NavUtils.makePerformerMoviesUrl(performer, extraCriteria?.movies)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function maybeRenderPopoverButtonGroup() {
|
function maybeRenderPopoverButtonGroup() {
|
||||||
if (
|
if (
|
||||||
performer.scene_count ||
|
performer.scene_count ||
|
||||||
performer.image_count ||
|
performer.image_count ||
|
||||||
performer.gallery_count ||
|
performer.gallery_count ||
|
||||||
performer.tags.length > 0
|
performer.tags.length > 0 ||
|
||||||
|
performer.movie_count
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<hr />
|
<hr />
|
||||||
<ButtonGroup className="card-popovers">
|
<ButtonGroup className="card-popovers">
|
||||||
{maybeRenderScenesPopoverButton()}
|
{maybeRenderScenesPopoverButton()}
|
||||||
|
{maybeRenderMoviesPopoverButton()}
|
||||||
{maybeRenderImagesPopoverButton()}
|
{maybeRenderImagesPopoverButton()}
|
||||||
{maybeRenderGalleriesPopoverButton()}
|
{maybeRenderGalleriesPopoverButton()}
|
||||||
{maybeRenderTagPopoverButton()}
|
{maybeRenderTagPopoverButton()}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useIntl } from "react-intl";
|
|||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
|
|
||||||
type PopoverLinkType = "scene" | "image" | "gallery";
|
type PopoverLinkType = "scene" | "image" | "gallery" | "movie";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
url: string;
|
url: string;
|
||||||
@@ -23,6 +23,8 @@ export const PopoverCountButton: React.FC<IProps> = ({ url, type, count }) => {
|
|||||||
return "image";
|
return "image";
|
||||||
case "gallery":
|
case "gallery":
|
||||||
return "images";
|
return "images";
|
||||||
|
case "movie":
|
||||||
|
return "film";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,6 +45,11 @@ export const PopoverCountButton: React.FC<IProps> = ({ url, type, count }) => {
|
|||||||
one: "gallery",
|
one: "gallery",
|
||||||
other: "galleries",
|
other: "galleries",
|
||||||
};
|
};
|
||||||
|
case "movie":
|
||||||
|
return {
|
||||||
|
one: "movie",
|
||||||
|
other: "movies",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,13 +89,31 @@ export const StudioCard: React.FC<IProps> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function maybeRenderMoviesPopoverButton() {
|
||||||
|
if (!studio.movie_count) return;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PopoverCountButton
|
||||||
|
type="movie"
|
||||||
|
count={studio.movie_count}
|
||||||
|
url={NavUtils.makeStudioMoviesUrl(studio)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function maybeRenderPopoverButtonGroup() {
|
function maybeRenderPopoverButtonGroup() {
|
||||||
if (studio.scene_count || studio.image_count || studio.gallery_count) {
|
if (
|
||||||
|
studio.scene_count ||
|
||||||
|
studio.image_count ||
|
||||||
|
studio.gallery_count ||
|
||||||
|
studio.movie_count
|
||||||
|
) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<hr />
|
<hr />
|
||||||
<ButtonGroup className="card-popovers">
|
<ButtonGroup className="card-popovers">
|
||||||
{maybeRenderScenesPopoverButton()}
|
{maybeRenderScenesPopoverButton()}
|
||||||
|
{maybeRenderMoviesPopoverButton()}
|
||||||
{maybeRenderImagesPopoverButton()}
|
{maybeRenderImagesPopoverButton()}
|
||||||
{maybeRenderGalleriesPopoverButton()}
|
{maybeRenderGalleriesPopoverButton()}
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export const StudioPerformersPanel: React.FC<IStudioPerformersPanel> = ({
|
|||||||
scenes: [studioCriterion],
|
scenes: [studioCriterion],
|
||||||
images: [studioCriterion],
|
images: [studioCriterion],
|
||||||
galleries: [studioCriterion],
|
galleries: [studioCriterion],
|
||||||
|
movies: [studioCriterion],
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -71,6 +71,21 @@ const makePerformerGalleriesUrl = (
|
|||||||
return `/galleries?${filter.makeQueryParameters()}`;
|
return `/galleries?${filter.makeQueryParameters()}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const makePerformerMoviesUrl = (
|
||||||
|
performer: Partial<GQL.PerformerDataFragment>,
|
||||||
|
extraCriteria?: Criterion<CriterionValue>[]
|
||||||
|
) => {
|
||||||
|
if (!performer.id) return "#";
|
||||||
|
const filter = new ListFilterModel(GQL.FilterMode.Movies);
|
||||||
|
const criterion = new PerformersCriterion();
|
||||||
|
criterion.value = [
|
||||||
|
{ id: performer.id, label: performer.name || `Performer ${performer.id}` },
|
||||||
|
];
|
||||||
|
filter.criteria.push(criterion);
|
||||||
|
addExtraCriteria(filter.criteria, extraCriteria);
|
||||||
|
return `/movies?${filter.makeQueryParameters()}`;
|
||||||
|
};
|
||||||
|
|
||||||
const makePerformersCountryUrl = (
|
const makePerformersCountryUrl = (
|
||||||
performer: Partial<GQL.PerformerDataFragment>
|
performer: Partial<GQL.PerformerDataFragment>
|
||||||
) => {
|
) => {
|
||||||
@@ -118,6 +133,18 @@ const makeStudioGalleriesUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
|||||||
return `/galleries?${filter.makeQueryParameters()}`;
|
return `/galleries?${filter.makeQueryParameters()}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const makeStudioMoviesUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
||||||
|
if (!studio.id) return "#";
|
||||||
|
const filter = new ListFilterModel(GQL.FilterMode.Movies);
|
||||||
|
const criterion = new StudiosCriterion();
|
||||||
|
criterion.value = {
|
||||||
|
items: [{ id: studio.id, label: studio.name || `Studio ${studio.id}` }],
|
||||||
|
depth: 0,
|
||||||
|
};
|
||||||
|
filter.criteria.push(criterion);
|
||||||
|
return `/movies?${filter.makeQueryParameters()}`;
|
||||||
|
};
|
||||||
|
|
||||||
const makeChildStudiosUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
const makeChildStudiosUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
||||||
if (!studio.id) return "#";
|
if (!studio.id) return "#";
|
||||||
const filter = new ListFilterModel(GQL.FilterMode.Studios);
|
const filter = new ListFilterModel(GQL.FilterMode.Studios);
|
||||||
@@ -226,10 +253,12 @@ export default {
|
|||||||
makePerformerScenesUrl,
|
makePerformerScenesUrl,
|
||||||
makePerformerImagesUrl,
|
makePerformerImagesUrl,
|
||||||
makePerformerGalleriesUrl,
|
makePerformerGalleriesUrl,
|
||||||
|
makePerformerMoviesUrl,
|
||||||
makePerformersCountryUrl,
|
makePerformersCountryUrl,
|
||||||
makeStudioScenesUrl,
|
makeStudioScenesUrl,
|
||||||
makeStudioImagesUrl,
|
makeStudioImagesUrl,
|
||||||
makeStudioGalleriesUrl,
|
makeStudioGalleriesUrl,
|
||||||
|
makeStudioMoviesUrl,
|
||||||
makeTagSceneMarkersUrl,
|
makeTagSceneMarkersUrl,
|
||||||
makeTagScenesUrl,
|
makeTagScenesUrl,
|
||||||
makeTagPerformersUrl,
|
makeTagPerformersUrl,
|
||||||
|
|||||||
Reference in New Issue
Block a user