Skip to content

Commit 86e5f3a

Browse files
TweeticoatsTweeticoats
andauthored
Adding a plugin to add extra performer information from wikidata. (#498)
Co-authored-by: Tweeticoats <[email protected]>
1 parent 4497e63 commit 86e5f3a

File tree

2 files changed

+297
-0
lines changed

2 files changed

+297
-0
lines changed
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
import stashapi.log as log
2+
from stashapi.stashapp import StashInterface
3+
import sys
4+
import json
5+
import time
6+
import re
7+
import requests
8+
9+
per_page = 100
10+
11+
settings = {
12+
"processWikidata":True,
13+
"wikidatExtraUrls":True,
14+
"awards": True,
15+
"otherInfo": True,
16+
"createTag": True
17+
18+
}
19+
20+
21+
wikidata_property_urls={
22+
# Claim P856 = Official Website, https://www.wikidata.org/wiki/Property:P856
23+
'P856': '%s',
24+
# P3351 Adult Film Database actor ID, https://www.wikidata.org/wiki/Property:P3351
25+
'P3351':'https://www.adultfilmdatabase.com/actor/wd-%s/',
26+
# P8809 = AIWARDS ID https://www.wikidata.org/wiki/Property:P8809
27+
'P8809': 'https://aiwards.com/%s',
28+
# P12776 = IAFD actor UUID https://www.wikidata.org/wiki/Property:P12776
29+
'P12776': 'https://www.iafd.com/person.rme/id=%s',
30+
# P2003 Instagram username https://www.wikidata.org/wiki/Property:P2003
31+
'P2003': 'https://www.instagram.com/_u/%s/',
32+
# P8604 OnlyFans username https://www.wikidata.org/wiki/Property:P8604
33+
'P8604': 'https://onlyfans.com/%s',
34+
# P4985 TMDB person ID https://www.wikidata.org/wiki/Property:P4985
35+
'P4985': 'https://www.themoviedb.org/person/%s',
36+
# P2002 X username https://www.wikidata.org/wiki/Property:P2002
37+
'P2002': 'https://x.com/%s',
38+
# P345 IMDb ID https://www.wikidata.org/wiki/Property:P345
39+
'P345': 'https://www.imdb.com/name/%s/',
40+
# P7085 TikTok username
41+
'P7085': 'https://www.tiktok.com/%s',
42+
# P12122 ManyVids ID
43+
'P12122': 'https://www.manyvids.com/Profile/%s/-/',
44+
# P12478 Brazzers ID
45+
'P12478': 'https://www.brazzers.com/pornstar/%s/_',
46+
# P11079 linktree
47+
'P11079': 'https://linktree.com/%s',
48+
# P5797 Twitch channel ID
49+
'P5797': ' https://www.twitch.tv/%s'
50+
}
51+
wikidata_field_properties={
52+
'P172': 'Ethnic group',
53+
'P19': 'Place of birth',
54+
'P106': 'Occupation',
55+
'P91': 'Sexual Orientation',
56+
'P69':'Educated At',
57+
'P102':'Member of political party',
58+
'P551':'Residence'
59+
}
60+
61+
62+
63+
request_wd = requests.Session()
64+
65+
wd_properties={}
66+
tags_cache={}
67+
68+
def getWDPPropertyLabel(propertyId):
69+
if propertyId not in wd_properties:
70+
property_url = 'https://www.wikidata.org/wiki/Special:EntityData/%s.json' % (propertyId,)
71+
wd2 = request_wd.get(property_url)
72+
73+
if wd2.status_code == 200:
74+
data2 = wd2.json()['entities'][propertyId]
75+
if 'en' in data2['labels']:
76+
wd_properties[propertyId]=data2['labels']['en']['value']
77+
return wd_properties[propertyId]
78+
else:
79+
wd_properties[propertyId]=''
80+
return wd_properties[propertyId]
81+
82+
83+
def processWikidata(performer,performer_update,url):
84+
wikidata_id=url[30:]
85+
api_url='https://www.wikidata.org/wiki/Special:EntityData/%s.json' % (wikidata_id,)
86+
log.debug('about to fetch wikidata url: %s' % (api_url,))
87+
wd=request_wd.get(api_url)
88+
if wd.status_code==200:
89+
# log.debug(wd.json().keys())
90+
data=wd.json()['entities'][wikidata_id]
91+
if settings['wikidatExtraUrls']:
92+
urls=[]
93+
for claim,urlstring in wikidata_property_urls.items():
94+
if claim in data['claims']:
95+
for c in data['claims'][claim]:
96+
# log.debug(claim)
97+
url = urlstring % (c['mainsnak']['datavalue']['value'],)
98+
if url not in performer['urls']:
99+
urls.append(url)
100+
101+
# log.debug(url)
102+
for k, v in data['sitelinks'].items():
103+
if v['url'] not in performer['urls']:
104+
urls.append(v['url'])
105+
if len(urls) > 0:
106+
if 'urls' not in performer_update:
107+
performer_update['urls'] = performer['urls']
108+
for url in urls:
109+
if url not in performer['urls']:
110+
performer_update['urls'].append(url)
111+
performer_update['update'] = True
112+
log.debug(performer_update)
113+
if settings['awards']:
114+
# award received (P166)
115+
# nominated for (P1411)
116+
for prop in ['P166','P1411']:
117+
if prop in data['claims']:
118+
for c in data['claims'][prop]:
119+
# log.debug(c)
120+
121+
award = {}
122+
award_id = c['mainsnak']['datavalue']['value']['id']
123+
124+
award['name']= getWDPPropertyLabel(award_id)
125+
126+
if 'qualifiers' in c:
127+
for q,qv in c['qualifiers'].items():
128+
# point in time
129+
# log.debug('q=%s qv=%s'% (q,qv,))
130+
if q=='P585':
131+
if len(qv)> 0:
132+
award['time']=qv[0]['datavalue']['value']['time'][1:5]
133+
# Subject of (the event name
134+
if q=='P805':
135+
award['venue'] = getWDPPropertyLabel(qv[0]['datavalue']['value']['id'])
136+
137+
if award:
138+
log.info('award: %s' % (award,))
139+
if 'custom_fields' not in performer_update:
140+
performer_update['custom_fields']={'full':performer['custom_fields']}
141+
award_name=award['name']
142+
award_value=award['name']
143+
if 'venue' in award and 'time' in award:
144+
award_value='%s - %s: %s' % (award['time'], award['venue'],award['name'],)
145+
elif 'time' in award:
146+
award_value='%s: %s' % (award['time'],award['name'],)
147+
elif 'venue' in award:
148+
award_value='%s: %s' % (award['venue'],award['name'],)
149+
if prop=='P1411':
150+
award_value='%s - Nominated' % award_value
151+
if award_name not in performer_update['custom_fields']['full']:
152+
performer_update['custom_fields']['full'][award_name]= award_value
153+
performer_update['update'] = True
154+
log.debug(performer_update)
155+
if settings['createTag']:
156+
if prop=='P166':
157+
performer_update['tag_names'].append('[Award Winner]')
158+
performer_update['update'] = True
159+
elif prop=='P1411':
160+
performer_update['tag_names'].append('[Award Nominated]')
161+
performer_update['update'] = True
162+
if settings['otherInfo']:
163+
for claim, label in wikidata_field_properties.items():
164+
if claim in data['claims']:
165+
claim_values=[]
166+
for c in data['claims'][claim]:
167+
# log.debug(c)
168+
claim_values.append(getWDPPropertyLabel(c['mainsnak']['datavalue']['value']['id']))
169+
if len(claim_values)> 0:
170+
if 'custom_fields' not in performer_update:
171+
performer_update['custom_fields'] = {'full': performer['custom_fields']}
172+
if label not in performer_update['custom_fields']['full']:
173+
performer_update['update'] = True
174+
performer_update['custom_fields']['full'][label] = ', '.join(claim_values)
175+
176+
177+
178+
def processPerformer(performer):
179+
180+
performer_update={'id':performer['id'],'update':False,"tag_names":[]}
181+
# log.debug(performer)
182+
for u in performer['urls']:
183+
if u.startswith('https://www.wikidata.org') and settings['processWikidata']:
184+
processWikidata(performer,performer_update,u)
185+
if performer_update['update']:
186+
log.debug('needs update')
187+
performer_update.pop('update')
188+
performer_update['tag_ids']=[x['id'] for x in performer['tags']]
189+
for t in performer_update['tag_names']:
190+
tt = stash.find_tag(t, create=True)
191+
if tt['id'] not in performer_update['tag_ids']:
192+
performer_update['tag_ids'].append(tt['id'])
193+
performer_update.pop('tag_names')
194+
195+
if settings['schema'] < 71:
196+
log.info('your version of stash does not support custom fields, a new version of stash should be released soon')
197+
# other features will still work for other versions
198+
performer_update.pop('custom_fields')
199+
log.info('updating performer: %s' % (performer_update,))
200+
stash.update_performer(performer_update)
201+
202+
def processPerformers():
203+
query={}
204+
count = stash.find_scenes(
205+
f=query,
206+
filter={"per_page": 1},
207+
get_count=True,
208+
)[0]
209+
210+
for r in range(1, int(count / per_page) + 2):
211+
i = (r - 1) * per_page
212+
log.info(
213+
"fetching data: %s - %s %0.1f%%"
214+
% (
215+
(r - 1) * per_page,
216+
r * per_page,
217+
(i / count) * 100,
218+
)
219+
)
220+
performers=stash.find_performers(filter={ "direction": "ASC", "page": r, "per_page": per_page, "sort": "created_at"})
221+
for performer in performers:
222+
processPerformer(performer)
223+
224+
225+
226+
227+
228+
229+
json_input = json.loads(sys.stdin.read())
230+
231+
FRAGMENT_SERVER = json_input["server_connection"]
232+
stash = StashInterface(FRAGMENT_SERVER)
233+
234+
res = stash.call_GQL("{systemStatus {databaseSchema databasePath}}")
235+
settings["schema"] = res["systemStatus"]["databaseSchema"]
236+
config = stash.get_configuration()["plugins"]
237+
238+
if "extraPerformerInfo" in config:
239+
settings.update(config["extraPerformerInfo"])
240+
log.info("config: %s " % (settings,))
241+
242+
243+
if "mode" in json_input["args"]:
244+
PLUGIN_ARGS = json_input["args"]["mode"]
245+
# log.debug(json_input)
246+
if "processAll" == PLUGIN_ARGS:
247+
if "performer_id" in json_input["args"]:
248+
performer=stash.find_performer(json_input["args"]["performer_id"])
249+
processPerformer(performer)
250+
else:
251+
processPerformers()
252+
253+
elif "hookContext" in json_input["args"]:
254+
id = json_input["args"]["hookContext"]["id"]
255+
if json_input["args"]["hookContext"]["type"] == "Performer.Update.Post":
256+
stash.run_plugin_task("extraPerformerInfo", "Process all", args={"performer_id": id})
257+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Extra Performer Info
2+
description: Add extra tags for VR and other ues
3+
version: 0.1
4+
url: https://github.com/stashapp/CommunityScripts/
5+
exec:
6+
- python
7+
- "{pluginDir}/extraPerformerInfo.py"
8+
interface: raw
9+
settings:
10+
processWikidata:
11+
displayName: process wikidata.org urls
12+
description: Enabling fetching info from wikidata
13+
type: BOOLEAN
14+
wikidatExtraUrls:
15+
displayName: Extra Urls
16+
description: Add extra porn related urls
17+
type: BOOLEAN
18+
awards:
19+
displayName: Add award info
20+
description: Add award info to custom fields if this has been added to wikidata
21+
type: BOOLEAN
22+
createTag:
23+
displayName: Add tags to performers
24+
description: Add [Award Winner], [Award Nominated] tags to performers
25+
type: BOOLEAN
26+
otherInfo:
27+
displayName: Add misc other info to custom fields
28+
description: Add other info such as birth place, ethnic group and Occupation to custom fields
29+
type: BOOLEAN
30+
31+
hooks:
32+
- name: Process performer
33+
description: Process wikidata or other api url
34+
triggeredBy:
35+
- Performer.Update.Post
36+
tasks:
37+
- name: Process all
38+
description: Process all scenes and add extra tags if configured
39+
defaultArgs:
40+
mode: processAll

0 commit comments

Comments
 (0)