mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 20:34:37 +03:00
Reload scrapers button (#592)
* Add reload scraper option to performer details * Add scraper reload to scene edit page * Show scene scraper menu when no queryable scrapers * Add 0.3 changelog
This commit is contained in:
3
graphql/documents/mutations/scrapers.graphql
Normal file
3
graphql/documents/mutations/scrapers.graphql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
mutation ReloadScrapers {
|
||||||
|
reloadScrapers
|
||||||
|
}
|
||||||
@@ -53,6 +53,7 @@ type Query {
|
|||||||
"""List available scrapers"""
|
"""List available scrapers"""
|
||||||
listPerformerScrapers: [Scraper!]!
|
listPerformerScrapers: [Scraper!]!
|
||||||
listSceneScrapers: [Scraper!]!
|
listSceneScrapers: [Scraper!]!
|
||||||
|
|
||||||
"""Scrape a list of performers based on name"""
|
"""Scrape a list of performers based on name"""
|
||||||
scrapePerformerList(scraper_id: ID!, query: String!): [ScrapedPerformer!]!
|
scrapePerformerList(scraper_id: ID!, query: String!): [ScrapedPerformer!]!
|
||||||
"""Scrapes a complete performer record based on a scrapePerformerList result"""
|
"""Scrapes a complete performer record based on a scrapePerformerList result"""
|
||||||
@@ -153,6 +154,9 @@ type Mutation {
|
|||||||
"""Clean metadata. Returns the job ID"""
|
"""Clean metadata. Returns the job ID"""
|
||||||
metadataClean: String!
|
metadataClean: String!
|
||||||
|
|
||||||
|
"""Reload scrapers"""
|
||||||
|
reloadScrapers: Boolean!
|
||||||
|
|
||||||
stopJob: Boolean!
|
stopJob: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
17
pkg/api/resolver_mutation_scraper.go
Normal file
17
pkg/api/resolver_mutation_scraper.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/stashapp/stash/pkg/scraper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *mutationResolver) ReloadScrapers(ctx context.Context) (bool, error) {
|
||||||
|
err := scraper.ReloadScrapers()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
@@ -50,6 +50,12 @@ func loadScrapers() ([]scraperConfig, error) {
|
|||||||
return scrapers, nil
|
return scrapers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReloadScrapers() error {
|
||||||
|
scrapers = nil
|
||||||
|
_, err := loadScrapers()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func ListPerformerScrapers() ([]*models.Scraper, error) {
|
func ListPerformerScrapers() ([]*models.Scraper, error) {
|
||||||
// read scraper config files from the directory and cache
|
// read scraper config files from the directory and cache
|
||||||
scrapers, err := loadScrapers()
|
scrapers, err := loadScrapers()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { useChangelogStorage } from "src/hooks";
|
import { useChangelogStorage } from "src/hooks";
|
||||||
import Version from "./Version";
|
import Version from "./Version";
|
||||||
import { V010, V011, V020, V021 } from "./versions";
|
import { V010, V011, V020, V021, V030 } from "./versions";
|
||||||
|
|
||||||
const Changelog: React.FC = () => {
|
const Changelog: React.FC = () => {
|
||||||
const [{ data, loading }, setOpenState] = useChangelogStorage();
|
const [{ data, loading }, setOpenState] = useChangelogStorage();
|
||||||
@@ -21,12 +21,19 @@ const Changelog: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1 className="mb-4">Changelog:</h1>
|
<h1 className="mb-4">Changelog:</h1>
|
||||||
|
<Version
|
||||||
|
version="v0.3.0"
|
||||||
|
openState={openState}
|
||||||
|
setOpenState={setVersionOpenState}
|
||||||
|
defaultOpen
|
||||||
|
>
|
||||||
|
<V030 />
|
||||||
|
</Version>
|
||||||
<Version
|
<Version
|
||||||
version="v0.2.1"
|
version="v0.2.1"
|
||||||
date="2020-06-10"
|
date="2020-06-10"
|
||||||
openState={openState}
|
openState={openState}
|
||||||
setOpenState={setVersionOpenState}
|
setOpenState={setVersionOpenState}
|
||||||
defaultOpen
|
|
||||||
>
|
>
|
||||||
<V021 />
|
<V021 />
|
||||||
</Version>
|
</Version>
|
||||||
@@ -35,7 +42,6 @@ const Changelog: React.FC = () => {
|
|||||||
date="2020-06-06"
|
date="2020-06-06"
|
||||||
openState={openState}
|
openState={openState}
|
||||||
setOpenState={setVersionOpenState}
|
setOpenState={setVersionOpenState}
|
||||||
defaultOpen
|
|
||||||
>
|
>
|
||||||
<V020 />
|
<V020 />
|
||||||
</Version>
|
</Version>
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ export { default as V010 } from "./v010";
|
|||||||
export { default as V011 } from "./v011";
|
export { default as V011 } from "./v011";
|
||||||
export { default as V020 } from "./v020";
|
export { default as V020 } from "./v020";
|
||||||
export { default as V021 } from "./v021";
|
export { default as V021 } from "./v021";
|
||||||
|
export { default as V030 } from "./v030";
|
||||||
|
|||||||
10
ui/v2.5/src/components/Changelog/versions/v030.tsx
Normal file
10
ui/v2.5/src/components/Changelog/versions/v030.tsx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import React from "react";
|
||||||
|
import ReactMarkdown from "react-markdown";
|
||||||
|
|
||||||
|
const markup = `
|
||||||
|
### 🎨 Improvements
|
||||||
|
* Add reload scrapers button.
|
||||||
|
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default () => <ReactMarkdown source={markup} />;
|
||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
stringToGender,
|
stringToGender,
|
||||||
queryScrapePerformer,
|
queryScrapePerformer,
|
||||||
queryScrapePerformerURL,
|
queryScrapePerformerURL,
|
||||||
|
mutateReloadScrapers,
|
||||||
} from "src/core/StashService";
|
} from "src/core/StashService";
|
||||||
import {
|
import {
|
||||||
Icon,
|
Icon,
|
||||||
@@ -224,10 +225,24 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
|
|||||||
ImageUtils.onImageChange(event, onImageLoad);
|
ImageUtils.onImageChange(event, onImageLoad);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDisplayFreeOnesDialog(scraper: GQL.Scraper) {
|
function onDisplayScrapeDialog(scraper: GQL.Scraper) {
|
||||||
setIsDisplayingScraperDialog(scraper);
|
setIsDisplayingScraperDialog(scraper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function onReloadScrapers() {
|
||||||
|
setIsLoading(true);
|
||||||
|
try {
|
||||||
|
await mutateReloadScrapers();
|
||||||
|
|
||||||
|
// reload the performer scrapers
|
||||||
|
await Scrapers.refetch();
|
||||||
|
} catch (e) {
|
||||||
|
Toast.error(e);
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getQueryScraperPerformerInput() {
|
function getQueryScraperPerformerInput() {
|
||||||
if (!scrapePerformerDetails) return {};
|
if (!scrapePerformerDetails) return {};
|
||||||
|
|
||||||
@@ -300,13 +315,21 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
|
|||||||
<Button
|
<Button
|
||||||
key={s.name}
|
key={s.name}
|
||||||
className="minimal"
|
className="minimal"
|
||||||
onClick={() => onDisplayFreeOnesDialog(s)}
|
onClick={() => onDisplayScrapeDialog(s)}
|
||||||
>
|
>
|
||||||
{s.name}
|
{s.name}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
: ""}
|
: ""}
|
||||||
|
<div>
|
||||||
|
<Button className="minimal" onClick={() => onReloadScrapers()}>
|
||||||
|
<span className="fa-icon">
|
||||||
|
<Icon icon="sync-alt" />
|
||||||
|
</span>
|
||||||
|
<span>Reload scrapers</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Popover.Content>
|
</Popover.Content>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
useListSceneScrapers,
|
useListSceneScrapers,
|
||||||
useSceneUpdate,
|
useSceneUpdate,
|
||||||
useSceneDestroy,
|
useSceneDestroy,
|
||||||
|
mutateReloadScrapers,
|
||||||
} from "src/core/StashService";
|
} from "src/core/StashService";
|
||||||
import {
|
import {
|
||||||
PerformerSelect,
|
PerformerSelect,
|
||||||
@@ -270,11 +271,21 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderScraperMenu() {
|
async function onReloadScrapers() {
|
||||||
if (!queryableScrapers || queryableScrapers.length === 0) {
|
setIsLoading(true);
|
||||||
return;
|
try {
|
||||||
|
await mutateReloadScrapers();
|
||||||
|
|
||||||
|
// reload the performer scrapers
|
||||||
|
await Scrapers.refetch();
|
||||||
|
} catch (e) {
|
||||||
|
Toast.error(e);
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderScraperMenu() {
|
||||||
return (
|
return (
|
||||||
<DropdownButton id="scene-scrape" title="Scrape with...">
|
<DropdownButton id="scene-scrape" title="Scrape with...">
|
||||||
{queryableScrapers.map((s) => (
|
{queryableScrapers.map((s) => (
|
||||||
@@ -282,6 +293,12 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
|||||||
{s.name}
|
{s.name}
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
))}
|
))}
|
||||||
|
<Dropdown.Item onClick={() => onReloadScrapers()}>
|
||||||
|
<span className="fa-icon">
|
||||||
|
<Icon icon="sync-alt" />
|
||||||
|
</span>
|
||||||
|
<span>Reload scrapers</span>
|
||||||
|
</Dropdown.Item>
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -410,6 +410,11 @@ export const queryScrapeScene = (
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const mutateReloadScrapers = () =>
|
||||||
|
client.mutate<GQL.ReloadScrapersMutation>({
|
||||||
|
mutation: GQL.ReloadScrapersDocument,
|
||||||
|
});
|
||||||
|
|
||||||
export const mutateMetadataScan = (input: GQL.ScanMetadataInput) =>
|
export const mutateMetadataScan = (input: GQL.ScanMetadataInput) =>
|
||||||
client.mutate<GQL.MetadataScanMutation>({
|
client.mutate<GQL.MetadataScanMutation>({
|
||||||
mutation: GQL.MetadataScanDocument,
|
mutation: GQL.MetadataScanDocument,
|
||||||
|
|||||||
@@ -424,6 +424,11 @@ div.dropdown-menu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.popover-body .btn .fa-icon,
|
||||||
|
.dropdown-item .fa-icon {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.brand-icon {
|
.brand-icon {
|
||||||
padding: 3px 6px;
|
padding: 3px 6px;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user