stash
This commit is contained in:
53
stash/config/scrapers/community/rb_common/graphql/README.md
Normal file
53
stash/config/scrapers/community/rb_common/graphql/README.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Common GraphQL
|
||||
|
||||
## Base Class
|
||||
|
||||
The base class is currently very basic, it requires the `faraday` gem and the logger for you. From there it defines a `query` method that can take up to two arguments. The first argument is your GraphQL query, and the second argument that defaults to nil if not provided is any variables that you would like to be passed with your query.
|
||||
|
||||
It defines a private `logger` method that is just a shorthand of the shared stash logger class `Stash::Logger`.
|
||||
|
||||
It defines a `standard_headers` method with:
|
||||
|
||||
```Ruby
|
||||
{
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json",
|
||||
"DNT": "1",
|
||||
}
|
||||
```
|
||||
|
||||
It is expected that any child classes define an `@extra_headers` variable on initialization with any ApiKey headers or such that may be required.
|
||||
|
||||
## Stash Interface
|
||||
|
||||
The Stash Interface has been designed so that raw queries should be written in HEREDOC format as private methods like for example:
|
||||
|
||||
```Ruby
|
||||
def gallery_path_query
|
||||
<<-'GRAPHQL'
|
||||
query FindGallery($id: ID!) {
|
||||
findGallery(id: $id) {
|
||||
path
|
||||
}
|
||||
}
|
||||
GRAPHQL
|
||||
end
|
||||
```
|
||||
|
||||
Those raw queries can then be called by any defined public methods like for example:
|
||||
|
||||
```Ruby
|
||||
def get_gallery_path(gallery_id)
|
||||
query(gallery_path_query, id_variables(gallery_id))["findGallery"]
|
||||
end
|
||||
```
|
||||
|
||||
As seem in the above example there is also a private helper method shorthand defined for when the variable passed to the query is just an ID:
|
||||
|
||||
```Ruby
|
||||
def id_variables(id)
|
||||
variables = {
|
||||
"id": id
|
||||
}
|
||||
end
|
||||
```
|
||||
@@ -0,0 +1,71 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Loading dependancies in a begin block so that we can give nice errors if they are missing
|
||||
begin
|
||||
# Logger should always be the first dependancy we try to load so that we know
|
||||
# if we can depend on it when logging other errors.
|
||||
require_relative "../logger"
|
||||
require 'faraday'
|
||||
rescue LoadError => error
|
||||
if error.message.match?(/logger$/)
|
||||
# If the logger isn't present, manually insert the level character when
|
||||
# logging (this is what the logger class from the file would have done for us)
|
||||
error_level_char = "\x01e\x02"
|
||||
STDERR.puts(error_level_char + "[GraphQL] Missing 'logger.rb' file in the rb_common folder.")
|
||||
exit
|
||||
end
|
||||
|
||||
logger = Stash::Logger
|
||||
if error.message.match?(/faraday$/)
|
||||
logger.error("[GraphQL] Faraday gem is not installed, please install it with 'gem install faraday'")
|
||||
else
|
||||
logger.error("[GraphQL] Unexpected error #{error.class} encountered: #{error.message}")
|
||||
end
|
||||
exit
|
||||
end
|
||||
|
||||
class GraphQLBase
|
||||
def query(query, variables = nil)
|
||||
headers = standard_api_headers.merge(@extra_headers)
|
||||
connection = Faraday.new(url: @url, headers: headers)
|
||||
response = connection.post do |request|
|
||||
body = { "query" => query }
|
||||
body["variables"] = variables if variables
|
||||
|
||||
request.body = body.to_json
|
||||
end
|
||||
|
||||
case response.status
|
||||
when 200
|
||||
result = JSON.parse(response.body)
|
||||
if result["error"]
|
||||
result["error"]["errors"].each do |error|
|
||||
logger.error("GraphQL error: #{error}")
|
||||
exit!
|
||||
end
|
||||
else
|
||||
result["data"]
|
||||
end
|
||||
when 401
|
||||
logger.error("[GraphQL] HTTP Error 401, Unauthorized. Make sure you have added an API Key in the 'config.rb' in the 'rb_common/configs' folder")
|
||||
return nil
|
||||
else
|
||||
logger.error("[GraphQL] Query failed: #{response.status} - #{response.body}")
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def logger
|
||||
Stash::Logger
|
||||
end
|
||||
|
||||
def standard_api_headers
|
||||
{
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json",
|
||||
"DNT": "1",
|
||||
}
|
||||
end
|
||||
end
|
||||
684
stash/config/scrapers/community/rb_common/graphql/stash.rb
Normal file
684
stash/config/scrapers/community/rb_common/graphql/stash.rb
Normal file
@@ -0,0 +1,684 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Loading dependancies in a begin block so that we can give nice errors if they are missing
|
||||
begin
|
||||
require_relative "graphql_base"
|
||||
require_relative "../configs/stash_config"
|
||||
rescue LoadError => error
|
||||
logger = Stash::Logger
|
||||
if error.message.match?(/graphql_base$/)
|
||||
logger.error("[GraphQL] Missing 'graphql/graphql_base.rb' file in the rb_common folder.")
|
||||
elsif error.message.match?(/configs\/stash_config$/)
|
||||
logger.error("[GraphQL] Missing 'configs/stash_config.rb' file in the rb_common folder.")
|
||||
else
|
||||
logger.error("[GraphQL] Unexpected error #{error.class} encountered: #{error.message}")
|
||||
end
|
||||
exit
|
||||
end
|
||||
|
||||
module GraphQL
|
||||
class Stash < GraphQLBase
|
||||
def initialize(referer: nil)
|
||||
@api_key = Config::Stash.api_key
|
||||
@url = Config::Stash.endpoint + "/graphql"
|
||||
@extra_headers = { "ApiKey": @api_key }
|
||||
@extra_headers["Referer"] = referer if referer
|
||||
end
|
||||
|
||||
def configuration
|
||||
query(configuration_query)["configuration"]
|
||||
end
|
||||
|
||||
def get_scene(scene_id)
|
||||
response = query(find_scene_query, id_variables(scene_id))["findScene"]
|
||||
end
|
||||
|
||||
def get_gallery(gallery_id)
|
||||
query(find_gallery_query, id_variables(gallery_id))["findGallery"]
|
||||
end
|
||||
|
||||
def get_gallery_path(gallery_id)
|
||||
query(gallery_path_query, id_variables(gallery_id))["findGallery"]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def id_variables(id)
|
||||
variables = {
|
||||
"id": id
|
||||
}
|
||||
end
|
||||
|
||||
def configuration_query
|
||||
<<-'GRAPHQL'
|
||||
query Configuration {
|
||||
configuration {
|
||||
...ConfigData
|
||||
}
|
||||
}
|
||||
fragment ConfigData on ConfigResult {
|
||||
general {
|
||||
...ConfigGeneralData
|
||||
}
|
||||
interface {
|
||||
...ConfigInterfaceData
|
||||
}
|
||||
dlna {
|
||||
...ConfigDLNAData
|
||||
}
|
||||
scraping {
|
||||
...ConfigScrapingData
|
||||
}
|
||||
defaults {
|
||||
...ConfigDefaultSettingsData
|
||||
}
|
||||
}
|
||||
fragment ConfigGeneralData on ConfigGeneralResult {
|
||||
stashes {
|
||||
path
|
||||
excludeVideo
|
||||
excludeImage
|
||||
}
|
||||
databasePath
|
||||
generatedPath
|
||||
metadataPath
|
||||
cachePath
|
||||
calculateMD5
|
||||
videoFileNamingAlgorithm
|
||||
parallelTasks
|
||||
previewAudio
|
||||
previewSegments
|
||||
previewSegmentDuration
|
||||
previewExcludeStart
|
||||
previewExcludeEnd
|
||||
previewPreset
|
||||
maxTranscodeSize
|
||||
maxStreamingTranscodeSize
|
||||
writeImageThumbnails
|
||||
apiKey
|
||||
username
|
||||
password
|
||||
maxSessionAge
|
||||
trustedProxies
|
||||
logFile
|
||||
logOut
|
||||
logLevel
|
||||
logAccess
|
||||
createGalleriesFromFolders
|
||||
videoExtensions
|
||||
imageExtensions
|
||||
galleryExtensions
|
||||
excludes
|
||||
imageExcludes
|
||||
customPerformerImageLocation
|
||||
scraperUserAgent
|
||||
scraperCertCheck
|
||||
scraperCDPPath
|
||||
stashBoxes {
|
||||
name
|
||||
endpoint
|
||||
api_key
|
||||
}
|
||||
}
|
||||
fragment ConfigInterfaceData on ConfigInterfaceResult {
|
||||
menuItems
|
||||
soundOnPreview
|
||||
wallShowTitle
|
||||
wallPlayback
|
||||
maximumLoopDuration
|
||||
noBrowser
|
||||
autostartVideo
|
||||
autostartVideoOnPlaySelected
|
||||
continuePlaylistDefault
|
||||
showStudioAsText
|
||||
css
|
||||
cssEnabled
|
||||
language
|
||||
slideshowDelay
|
||||
disabledDropdownCreate {
|
||||
performer
|
||||
tag
|
||||
studio
|
||||
}
|
||||
handyKey
|
||||
funscriptOffset
|
||||
}
|
||||
fragment ConfigDLNAData on ConfigDLNAResult {
|
||||
serverName
|
||||
enabled
|
||||
whitelistedIPs
|
||||
interfaces
|
||||
}
|
||||
fragment ConfigScrapingData on ConfigScrapingResult {
|
||||
scraperUserAgent
|
||||
scraperCertCheck
|
||||
scraperCDPPath
|
||||
excludeTagPatterns
|
||||
}
|
||||
fragment ConfigDefaultSettingsData on ConfigDefaultSettingsResult {
|
||||
scan {
|
||||
useFileMetadata
|
||||
stripFileExtension
|
||||
scanGeneratePreviews
|
||||
scanGenerateImagePreviews
|
||||
scanGenerateSprites
|
||||
scanGeneratePhashes
|
||||
scanGenerateThumbnails
|
||||
}
|
||||
identify {
|
||||
sources {
|
||||
source {
|
||||
...ScraperSourceData
|
||||
}
|
||||
options {
|
||||
...IdentifyMetadataOptionsData
|
||||
}
|
||||
}
|
||||
options {
|
||||
...IdentifyMetadataOptionsData
|
||||
}
|
||||
}
|
||||
autoTag {
|
||||
performers
|
||||
studios
|
||||
tags
|
||||
__typename
|
||||
}
|
||||
generate {
|
||||
sprites
|
||||
previews
|
||||
imagePreviews
|
||||
previewOptions {
|
||||
previewSegments
|
||||
previewSegmentDuration
|
||||
previewExcludeStart
|
||||
previewExcludeEnd
|
||||
previewPreset
|
||||
}
|
||||
markers
|
||||
markerImagePreviews
|
||||
markerScreenshots
|
||||
transcodes
|
||||
phashes
|
||||
}
|
||||
deleteFile
|
||||
deleteGenerated
|
||||
}
|
||||
fragment ScraperSourceData on ScraperSource {
|
||||
stash_box_index
|
||||
stash_box_endpoint
|
||||
scraper_id
|
||||
}
|
||||
fragment IdentifyMetadataOptionsData on IdentifyMetadataOptions {
|
||||
fieldOptions {
|
||||
...IdentifyFieldOptionsData
|
||||
}
|
||||
setCoverImage
|
||||
setOrganized
|
||||
includeMalePerformers
|
||||
}
|
||||
fragment IdentifyFieldOptionsData on IdentifyFieldOptions {
|
||||
field
|
||||
strategy
|
||||
createMissing
|
||||
}
|
||||
GRAPHQL
|
||||
end
|
||||
|
||||
def find_scene_query
|
||||
<<-'GRAPHQL'
|
||||
query FindScene($id: ID!, $checksum: String) {
|
||||
findScene(id: $id, checksum: $checksum) {
|
||||
...SceneData
|
||||
}
|
||||
}
|
||||
fragment SceneData on Scene {
|
||||
id
|
||||
checksum
|
||||
oshash
|
||||
title
|
||||
details
|
||||
url
|
||||
date
|
||||
rating
|
||||
o_counter
|
||||
organized
|
||||
path
|
||||
phash
|
||||
interactive
|
||||
file {
|
||||
size
|
||||
duration
|
||||
video_codec
|
||||
audio_codec
|
||||
width
|
||||
height
|
||||
framerate
|
||||
bitrate
|
||||
}
|
||||
paths {
|
||||
screenshot
|
||||
preview
|
||||
stream
|
||||
webp
|
||||
vtt
|
||||
chapters_vtt
|
||||
sprite
|
||||
funscript
|
||||
}
|
||||
scene_markers {
|
||||
...SceneMarkerData
|
||||
}
|
||||
galleries {
|
||||
...SlimGalleryData
|
||||
}
|
||||
studio {
|
||||
...SlimStudioData
|
||||
}
|
||||
movies {
|
||||
movie {
|
||||
...MovieData
|
||||
}
|
||||
scene_index
|
||||
}
|
||||
tags {
|
||||
...SlimTagData
|
||||
}
|
||||
performers {
|
||||
...PerformerData
|
||||
}
|
||||
stash_ids {
|
||||
endpoint
|
||||
stash_id
|
||||
}
|
||||
}
|
||||
fragment SceneMarkerData on SceneMarker {
|
||||
id
|
||||
title
|
||||
seconds
|
||||
stream
|
||||
preview
|
||||
screenshot
|
||||
scene {
|
||||
id
|
||||
}
|
||||
primary_tag {
|
||||
id
|
||||
name
|
||||
aliases
|
||||
}
|
||||
tags {
|
||||
id
|
||||
name
|
||||
aliases
|
||||
}
|
||||
}
|
||||
fragment SlimGalleryData on Gallery {
|
||||
id
|
||||
checksum
|
||||
path
|
||||
title
|
||||
date
|
||||
url
|
||||
details
|
||||
rating
|
||||
organized
|
||||
image_count
|
||||
cover {
|
||||
file {
|
||||
size
|
||||
width
|
||||
height
|
||||
}
|
||||
paths {
|
||||
thumbnail
|
||||
}
|
||||
}
|
||||
studio {
|
||||
id
|
||||
name
|
||||
image_path
|
||||
}
|
||||
tags {
|
||||
id
|
||||
name
|
||||
}
|
||||
performers {
|
||||
id
|
||||
name
|
||||
gender
|
||||
favorite
|
||||
image_path
|
||||
}
|
||||
scenes {
|
||||
id
|
||||
title
|
||||
path
|
||||
}
|
||||
}
|
||||
fragment SlimStudioData on Studio {
|
||||
id
|
||||
name
|
||||
image_path
|
||||
stash_ids {
|
||||
endpoint
|
||||
stash_id
|
||||
}
|
||||
parent_studio {
|
||||
id
|
||||
}
|
||||
details
|
||||
rating
|
||||
aliases
|
||||
}
|
||||
fragment MovieData on Movie {
|
||||
id
|
||||
checksum
|
||||
name
|
||||
aliases
|
||||
duration
|
||||
date
|
||||
rating
|
||||
director
|
||||
studio {
|
||||
...SlimStudioData
|
||||
}
|
||||
synopsis
|
||||
url
|
||||
front_image_path
|
||||
back_image_path
|
||||
scene_count
|
||||
scenes {
|
||||
id
|
||||
title
|
||||
path
|
||||
}
|
||||
}
|
||||
fragment SlimTagData on Tag {
|
||||
id
|
||||
name
|
||||
aliases
|
||||
image_path
|
||||
}
|
||||
fragment PerformerData on Performer {
|
||||
id
|
||||
checksum
|
||||
name
|
||||
url
|
||||
gender
|
||||
twitter
|
||||
instagram
|
||||
birthdate
|
||||
ethnicity
|
||||
country
|
||||
eye_color
|
||||
height
|
||||
measurements
|
||||
fake_tits
|
||||
career_length
|
||||
tattoos
|
||||
piercings
|
||||
aliases
|
||||
favorite
|
||||
image_path
|
||||
scene_count
|
||||
image_count
|
||||
gallery_count
|
||||
movie_count
|
||||
tags {
|
||||
...SlimTagData
|
||||
}
|
||||
stash_ids {
|
||||
stash_id
|
||||
endpoint
|
||||
}
|
||||
rating
|
||||
details
|
||||
death_date
|
||||
hair_color
|
||||
weight
|
||||
}
|
||||
GRAPHQL
|
||||
end
|
||||
|
||||
def find_gallery_query
|
||||
<<-'GRAPHQL'
|
||||
query FindGallery($id: ID!) {
|
||||
findGallery(id: $id) {
|
||||
...GalleryData
|
||||
}
|
||||
}
|
||||
fragment GalleryData on Gallery {
|
||||
id
|
||||
checksum
|
||||
path
|
||||
created_at
|
||||
updated_at
|
||||
title
|
||||
date
|
||||
url
|
||||
details
|
||||
rating
|
||||
organized
|
||||
images {
|
||||
...SlimImageData
|
||||
}
|
||||
cover {
|
||||
...SlimImageData
|
||||
}
|
||||
studio {
|
||||
...SlimStudioData
|
||||
}
|
||||
tags {
|
||||
...SlimTagData
|
||||
}
|
||||
|
||||
performers {
|
||||
...PerformerData
|
||||
}
|
||||
scenes {
|
||||
...SlimSceneData
|
||||
}
|
||||
}
|
||||
fragment SlimImageData on Image {
|
||||
id
|
||||
checksum
|
||||
title
|
||||
rating
|
||||
organized
|
||||
o_counter
|
||||
path
|
||||
|
||||
file {
|
||||
size
|
||||
width
|
||||
height
|
||||
}
|
||||
|
||||
paths {
|
||||
thumbnail
|
||||
image
|
||||
}
|
||||
|
||||
galleries {
|
||||
id
|
||||
path
|
||||
title
|
||||
}
|
||||
|
||||
studio {
|
||||
id
|
||||
name
|
||||
image_path
|
||||
}
|
||||
|
||||
tags {
|
||||
id
|
||||
name
|
||||
}
|
||||
|
||||
performers {
|
||||
id
|
||||
name
|
||||
gender
|
||||
favorite
|
||||
image_path
|
||||
}
|
||||
}
|
||||
fragment SlimStudioData on Studio {
|
||||
id
|
||||
name
|
||||
image_path
|
||||
stash_ids {
|
||||
endpoint
|
||||
stash_id
|
||||
}
|
||||
parent_studio {
|
||||
id
|
||||
}
|
||||
details
|
||||
rating
|
||||
aliases
|
||||
}
|
||||
fragment SlimTagData on Tag {
|
||||
id
|
||||
name
|
||||
aliases
|
||||
image_path
|
||||
}
|
||||
fragment PerformerData on Performer {
|
||||
id
|
||||
checksum
|
||||
name
|
||||
url
|
||||
gender
|
||||
twitter
|
||||
instagram
|
||||
birthdate
|
||||
ethnicity
|
||||
country
|
||||
eye_color
|
||||
height
|
||||
measurements
|
||||
fake_tits
|
||||
career_length
|
||||
tattoos
|
||||
piercings
|
||||
aliases
|
||||
favorite
|
||||
image_path
|
||||
scene_count
|
||||
image_count
|
||||
gallery_count
|
||||
movie_count
|
||||
|
||||
tags {
|
||||
...SlimTagData
|
||||
}
|
||||
|
||||
stash_ids {
|
||||
stash_id
|
||||
endpoint
|
||||
}
|
||||
rating
|
||||
details
|
||||
death_date
|
||||
hair_color
|
||||
weight
|
||||
}
|
||||
fragment SlimSceneData on Scene {
|
||||
id
|
||||
checksum
|
||||
oshash
|
||||
title
|
||||
details
|
||||
url
|
||||
date
|
||||
rating
|
||||
o_counter
|
||||
organized
|
||||
path
|
||||
phash
|
||||
interactive
|
||||
|
||||
file {
|
||||
size
|
||||
duration
|
||||
video_codec
|
||||
audio_codec
|
||||
width
|
||||
height
|
||||
framerate
|
||||
bitrate
|
||||
}
|
||||
|
||||
paths {
|
||||
screenshot
|
||||
preview
|
||||
stream
|
||||
webp
|
||||
vtt
|
||||
chapters_vtt
|
||||
sprite
|
||||
funscript
|
||||
}
|
||||
|
||||
scene_markers {
|
||||
id
|
||||
title
|
||||
seconds
|
||||
}
|
||||
|
||||
galleries {
|
||||
id
|
||||
path
|
||||
title
|
||||
}
|
||||
|
||||
studio {
|
||||
id
|
||||
name
|
||||
image_path
|
||||
}
|
||||
|
||||
movies {
|
||||
movie {
|
||||
id
|
||||
name
|
||||
front_image_path
|
||||
}
|
||||
scene_index
|
||||
}
|
||||
|
||||
tags {
|
||||
id
|
||||
name
|
||||
}
|
||||
|
||||
performers {
|
||||
id
|
||||
name
|
||||
gender
|
||||
favorite
|
||||
image_path
|
||||
}
|
||||
|
||||
stash_ids {
|
||||
endpoint
|
||||
stash_id
|
||||
}
|
||||
}
|
||||
GRAPHQL
|
||||
end
|
||||
|
||||
def gallery_path_query
|
||||
<<-'GRAPHQL'
|
||||
query FindGallery($id: ID!) {
|
||||
findGallery(id: $id) {
|
||||
path
|
||||
}
|
||||
}
|
||||
GRAPHQL
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user