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:
WithoutPants
2020-06-10 13:43:17 +10:00
committed by GitHub
parent 32011aa86f
commit d8ce137086
11 changed files with 106 additions and 9 deletions

View File

@@ -0,0 +1,3 @@
mutation ReloadScrapers {
reloadScrapers
}

View File

@@ -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!
} }

View 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
}

View File

@@ -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()

View File

@@ -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>

View File

@@ -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";

View 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} />;

View File

@@ -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>

View File

@@ -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>
); );
} }

View File

@@ -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,

View File

@@ -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;