|
| 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 | + |
0 commit comments