This commit is contained in:
Christoph Califice
2025-10-09 20:05:31 -03:00
parent ed22ef22bc
commit 0a5f88d75a
1442 changed files with 101562 additions and 0 deletions

View File

@@ -0,0 +1,192 @@
import json
import sys
import re
from urllib.parse import urlparse
import requests
from datetime import datetime
# initialize the session for making requests
session = requests.session()
try:
import py_common.log as log
except ModuleNotFoundError:
print(
"You need to download the folder 'py_common' from the community repo (CommunityScrapers/tree/master/scrapers/py_common)",
file=sys.stderr,
)
sys.exit(1)
# --------------------------------------------
# This is a scraper for: RealityLovers sites
#
def performerByURL():
# read the input. A URL must be passed in for the sceneByURL call
inp = json.loads(sys.stdin.read())
actor_id = re.sub(r".*/([0-9]*)/.*", r"\1", inp["url"])
if not actor_id:
log.error("No actor ID found in URL")
return {}
domain = urlparse(inp["url"]).netloc.replace("www.", "")
api_url = f"https://engine.{domain}/content/actor?actorId={actor_id}"
# Making some assumptions here
gender = "TRANSGENDER_FEMALE" if "tsvirtuallovers" in domain else "FEMALE"
scraped = session.get(api_url)
scraped.raise_for_status()
log.trace("Scraped the url: " + api_url)
data = scraped.json()
performer = {
"name": data["name"],
"image": re.sub(
r".*,(\S+).*", r"\1", data["screenshots"][0]["galleryImgSrcSet"]
),
"gender": gender,
}
if birthdate := data.get("birthDay"):
performer["birthdate"] = birthdate
if country := data.get("country"):
performer["country"] = country
if measurements := data.get("cupSize"):
performer["measurements"] = measurements
if height := data.get("height"):
performer["height"] = height
if weight := data.get("weight"):
performer["weight"] = weight
if details := data.get("description"):
performer["details"] = details
if tags := [{"name": x["name"]} for x in data.get("categories", [])]:
performer["tags"] = tags
if twitter := data.get("twitterLink"):
performer["twitter"] = twitter
if instagram := data.get("instagramLink"):
performer["instagram"] = instagram
return performer
def sceneByURL():
# read the input. A URL must be passed in for the sceneByURL call
inp = json.loads(sys.stdin.read())
scene_id = re.sub(r".*/([0-9]*)/.*", r"\1", inp["url"])
if not scene_id:
log.error("No scene ID found in URL")
return {}
domain = urlparse(inp["url"]).netloc.replace("www.", "")
studio = "Reality Lovers"
if "tsvirtuallovers" in domain:
studio = "TS Virtual Lovers"
api_url = f"https://engine.{domain}/content/videoDetail?contentId={scene_id}"
scraped = session.get(api_url)
if scraped.status_code >= 400:
log.error("HTTP Error: %s" % scraped.status_code)
return {}
log.trace("Scraped the url: " + api_url)
data = scraped.json()
# log.debug(json.dumps(data))
title = re.sub(r'\s+VR Porn Video$', '', data["title"])
details = data["description"]
# image
image_urls = [
src_set.split(' ')[0] for src_set in data["mainImages"][0]["imgSrcSet"].split(',')
]
# pick highest available quality, or fall back to first image
suffixes = ['ultra.jpg', 'big.jpg', 'high.jpg', 'medium.jpg', 'small.jpg']
image_url = next((url for suffix in suffixes for url in image_urls if url.endswith(suffix)), image_urls[0])
date = data["releaseDate"]
# tags
tags = [{"name": x["name"]} for x in data["categories"]]
tags.append({'name': 'Virtual Reality'})
if data["mainImages"][0]["perspective"] == 'VOYEUR':
tags.extend([{'name': 'Non-POV'}, {'name': 'Voyeur'}])
actors = [
{"name": x["name"], "url": f"https://{domain}/{x['uri']}"}
for x in data["starring"]
]
# create our output
return {
"title": title,
"date": date,
"tags": tags,
"details": details,
"image": image_url,
"studio": {"name": studio},
"performers": actors,
}
# Get the scene by the fragment. The title is used as the search field. Should return the JSON response.
def sceneByName():
# read the input. A title or name must be passed in
inp = json.loads(sys.stdin.read())
log.trace("Input: " + json.dumps(inp))
query_value = inp["title"] if "title" in inp else inp["name"]
if not query_value:
log.error("No title or name Entered")
return []
log.trace("Query Value: " + query_value)
# No way to know if the user wanted to search realitylovers or tsvirtuallovers, so search both
raw_scenes = []
for domain in ("realitylovers.com", "tsvirtuallovers.com"):
api_url = f"https://engine.{domain}/content/search?max=100000&page=0&pornstar=0&category=0&s={query_value}"
scraped_scenes = session.get(api_url)
scraped_scenes.raise_for_status()
scenes = scraped_scenes.json()
new_scenes = [{"domain": domain, **s} for s in scenes["contents"]]
log.debug(f"Found {len(new_scenes)} scenes from {domain}")
raw_scenes.extend(new_scenes)
results = []
for scene in raw_scenes:
# Parse the date published. Get rid of the 'st' (like in 1st) via a regex. ex: "Sep 27th 2018"
cleandate = re.sub(r"(st|nd|rd|th)", r"", scene["released"])
date = datetime.strptime(cleandate, "%b %d %Y").strftime("%Y-%m-%d")
main_image_src = re.sub(r".*1x,(.*) 2x", r"\1", scene["mainImageSrcset"])
# Add the new scene to the results
results.append(
{
"Title": scene["title"],
"URL": f"https://{scene['domain']}/{scene['videoUri']}",
"Image": main_image_src,
"Date": date,
}
)
return results
# Figure out what was invoked by Stash and call the correct thing
if sys.argv[1] == "performerByURL":
print(json.dumps(performerByURL()))
elif sys.argv[1] in ("sceneByURL", "sceneByQueryFragment"):
print(json.dumps(sceneByURL()))
elif sys.argv[1] == "sceneByName":
scenes = sceneByName()
print(json.dumps(scenes))
elif sys.argv[1] == "sceneByFragment":
scenes = sceneByName()
if len(scenes) > 0:
# return the first query result
print(json.dumps(scenes[0]))
else:
# empty array for no results
log.info("No results")
print("{}")
else:
log.error("Unknown argument passed: " + sys.argv[1])
print(json.dumps({}))

View File

@@ -0,0 +1,41 @@
name: RealityLovers
# requires: py_common
# scrapes: Reality Lovers, TS Virtual Lovers
performerByURL:
- action: script
url:
- https://realitylovers.com/girl
- https://tsvirtuallovers.com/girl
script:
- python
- RealityLovers.py
- performerByURL
sceneByURL:
- action: script
url:
- https://realitylovers.com/vd/
- https://tsvirtuallovers.com/vd/
script:
- python
- RealityLovers.py
- sceneByURL
sceneByName:
action: script
script:
- python
- RealityLovers.py
- sceneByName
sceneByQueryFragment:
action: script
script:
- python
- RealityLovers.py
- sceneByQueryFragment
sceneByFragment:
action: script
script:
- python
- RealityLovers.py
- sceneByFragment
# Last Updated February 28, 2024

View File

@@ -0,0 +1,10 @@
id: RealityLovers
name: RealityLovers
metadata: {}
version: e531e87
date: "2024-02-28 15:14:32"
requires: []
source_repository: https://stashapp.github.io/CommunityScrapers/stable/index.yml
files:
- RealityLovers.yml
- RealityLovers.py