mirror of
https://github.com/stashapp/CommunityScripts.git
synced 2026-04-16 22:03:17 -05:00
Add plugin Adulttime Interactive Downloader (#240)
* Create requirements.txt * Add files via upload * Create empty * Yarned Files modified: plugins/AdulttimeInteractiveDL/AdulttimeInteractiveDL.py modified: plugins/AdulttimeInteractiveDL/AdulttimeInteractiveDL.yml deleted: plugins/AdulttimeInteractiveDL/cache/empty modified: plugins/AdulttimeInteractiveDL/requirements.txt * - Added Return on Error with stashapi modified: plugins/AdulttimeInteractiveDL/AdulttimeInteractiveDL.py - Add new Plugin "PythonToolsInstaller" for Docker ENV, to create VENV with stashtools to use with other Plugins new file: plugins/PythonToolsInstaller/PythonToolsInstaller.py new file: plugins/PythonToolsInstaller/PythonToolsInstaller.yml new file: plugins/PythonToolsInstaller/packages/stashtools.txt Files yarned.
This commit is contained in:
278
plugins/AdulttimeInteractiveDL/AdulttimeInteractiveDL.py
Normal file
278
plugins/AdulttimeInteractiveDL/AdulttimeInteractiveDL.py
Normal file
@@ -0,0 +1,278 @@
|
||||
import requests, os, shutil
|
||||
import re, sys, json
|
||||
import datetime as dt
|
||||
import pathlib
|
||||
import time
|
||||
from inspect import getmembers, isfunction
|
||||
|
||||
CurRunDir = pathlib.Path(__file__).parent.resolve()
|
||||
vENVDir = f"{CurRunDir}/../PythonToolsInstaller/venv/lib/python3.11/site-packages"
|
||||
|
||||
try:
|
||||
if os.path.isdir(vENVDir):
|
||||
print(f"VENV Dir {vENVDir} used", file=sys.stderr)
|
||||
sys.path.insert(0, vENVDir)
|
||||
else:
|
||||
print(f"VENV Dir {vENVDir} not used", file=sys.stderr)
|
||||
|
||||
except Exception as e:
|
||||
# Ignore
|
||||
print("Hey there...")
|
||||
|
||||
try:
|
||||
import stashapi.log as log
|
||||
from stashapi.tools import human_bytes, human_bits
|
||||
from stashapi.stash_types import PhashDistance
|
||||
from stashapi.stashapp import StashInterface
|
||||
|
||||
except ModuleNotFoundError:
|
||||
print(
|
||||
"You need to install the stashapi module. (pip install stashapp-tools)",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return
|
||||
|
||||
FAKTORCONV = 6.25
|
||||
FRAGMENT = json.loads(sys.stdin.read())
|
||||
# MODE = FRAGMENT['args']['mode']
|
||||
MODE = FRAGMENT["args"].get("mode")
|
||||
PLUGIN_DIR = FRAGMENT["server_connection"]["PluginDir"]
|
||||
stash = StashInterface(FRAGMENT["server_connection"])
|
||||
|
||||
SLIM_SCENE_FRAGMENT = """
|
||||
id
|
||||
title
|
||||
url
|
||||
urls
|
||||
details
|
||||
date
|
||||
tags { id }
|
||||
studio{
|
||||
name
|
||||
stash_ids{
|
||||
endpoint
|
||||
stash_id
|
||||
}
|
||||
}
|
||||
files {
|
||||
size
|
||||
path
|
||||
width
|
||||
height
|
||||
bit_rate
|
||||
mod_time
|
||||
duration
|
||||
frame_rate
|
||||
video_codec
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
log.info(f"Plugin Dir {PLUGIN_DIR} ")
|
||||
cachepath = os.path.join(PLUGIN_DIR, "cache")
|
||||
|
||||
try:
|
||||
os.makedirs(cachepath, exist_ok=True)
|
||||
print("Directory '%s' created successfully" % cachepath)
|
||||
except OSError as error:
|
||||
print("Directory '%s' can not be created" % cachepath)
|
||||
|
||||
if MODE:
|
||||
if MODE == "download":
|
||||
get_download()
|
||||
if MODE == "disable":
|
||||
return true
|
||||
else:
|
||||
FRAGMENT_HOOK_TYPE = FRAGMENT["args"]["hookContext"]["type"]
|
||||
FRAGMENT_SCENE_ID = FRAGMENT["args"]["hookContext"]["id"]
|
||||
try:
|
||||
get_download() # ToDo use single Scene
|
||||
except Exception as err:
|
||||
log.LogError(f"main function error: {err}")
|
||||
traceback.print_exc()
|
||||
|
||||
log.exit("Plugin exited normally.")
|
||||
|
||||
|
||||
def parse_timestamp(ts, format="%Y-%m-%dT%H:%M:%S%z"):
|
||||
ts = re.sub(r"\.\d+", "", ts) # remove fractional seconds
|
||||
return dt.datetime.strptime(ts, format)
|
||||
|
||||
|
||||
def get_download():
|
||||
|
||||
cachepath = os.path.join(PLUGIN_DIR, "cache")
|
||||
log.info(f"Plugin Cachepath {cachepath} ")
|
||||
|
||||
# adulttime.com
|
||||
# jerkbuddies.com
|
||||
# adulttime.studio
|
||||
# oopsie.tube
|
||||
# adulttimepilots.com
|
||||
# kissmefuckme.net
|
||||
# youngerloverofmine.com
|
||||
# dareweshare.net
|
||||
# milfoverload.net
|
||||
# getupclose.com
|
||||
# https://switch.com/en/video/switch/Switch-Awakening/234167
|
||||
# https://howwomenorgasm.com/en/video/howwomenorgasm/How-Women-Orgasm---Lumi-Ray/230015
|
||||
|
||||
scene_count, scenes = stash.find_scenes(
|
||||
# f={"url": {"modifier": "INCLUDES", "value": "adulttime.com"}},
|
||||
f={
|
||||
"url": {
|
||||
"modifier": "MATCHES_REGEX",
|
||||
"value": "howwomenorgasm\\.com|switch\\.com|getupclose\\.com|milfoverload\\.net|dareweshare\\.net|jerkbuddies\\.com|adulttime\\.studio|adulttime\\.com|oopsie\\.tube|adulttimepilots\\.com|kissmefuckme\\.net|youngerloverofmine\\.com",
|
||||
}
|
||||
},
|
||||
fragment=SLIM_SCENE_FRAGMENT,
|
||||
get_count=True,
|
||||
)
|
||||
|
||||
log.info(f"Plugin found {scene_count} Scenes from Adulttime ")
|
||||
|
||||
i = 0
|
||||
for i, scene in enumerate(scenes):
|
||||
title = re.sub(r"\[PDT: .+?\]\s+", "", scene["title"])
|
||||
url = scene["url"]
|
||||
urls = scene["urls"]
|
||||
|
||||
for u in urls:
|
||||
# if re.search(r"members\.adulttime\.com", u):
|
||||
if re.search(r"\.adulttime\.com", u):
|
||||
aid = re.search(r"\/([0-9]+)", u)
|
||||
aid = aid.group(1)
|
||||
fpw = f"{cachepath}/{aid}.json"
|
||||
fppatw = f"{cachepath}/{aid}.pat"
|
||||
fpfunw = f"{cachepath}/{aid}.funscript"
|
||||
log.debug(f"Found Adulttime URL {u} width Provider ID {aid}")
|
||||
|
||||
# Try to DL or open from Cache
|
||||
if os.path.isfile(fpw) == False:
|
||||
dlurl = f"https://coll.lovense.com/coll-log/video-websites/get/pattern?videoId={aid}&pf=Adulttime"
|
||||
r = requests.get(dlurl, allow_redirects=True)
|
||||
log.debug(r.content)
|
||||
dlapires = json.loads(r.content)
|
||||
open(fpw, "w+").write(r.content.decode("utf-8"))
|
||||
else:
|
||||
|
||||
with open(fpw, "r") as f:
|
||||
dlapires = json.load(f)
|
||||
|
||||
try:
|
||||
|
||||
if dlapires["code"] == 0:
|
||||
log.info(f"Try Interactive for this ID")
|
||||
|
||||
if os.path.isfile(fppatw) == False:
|
||||
dlpaturl = dlapires["data"]["pattern"]
|
||||
rpat = requests.get(dlpaturl, allow_redirects=True)
|
||||
open(fppatw, "w+").write(
|
||||
rpat.content.decode("utf-8")
|
||||
)
|
||||
|
||||
if os.path.isfile(fpfunw) == False:
|
||||
convert_lovense_to_funscript(
|
||||
scene, fppatw, fpfunw
|
||||
)
|
||||
|
||||
map_file_with_funscript(scene, fpfunw)
|
||||
|
||||
else:
|
||||
log.debug(f"No Interactive for this ID")
|
||||
|
||||
except KeyError as error:
|
||||
log.error(
|
||||
"File '%s' can not be read, invailed format" % fpw
|
||||
)
|
||||
fullfile = json.dumps(dlapires)
|
||||
if re.search("Too many requests", fullfile) or re.search(
|
||||
"security", fullfile
|
||||
):
|
||||
os.remove(fpw)
|
||||
log.error("Too many requests. Wait a moment...")
|
||||
time.sleep(60)
|
||||
|
||||
log.progress(i / scene_count)
|
||||
i = i + 1
|
||||
|
||||
|
||||
def map_file_with_funscript(sceneinfo, funscriptfile):
|
||||
|
||||
scenefiles = sceneinfo["files"]
|
||||
for u in scenefiles:
|
||||
filepath = os.path.dirname(os.path.abspath(u["path"]))
|
||||
filename = os.path.basename(u["path"])
|
||||
filenamewithoutext = filename.rsplit(".", maxsplit=1)[0]
|
||||
funscriptnewname = f"{filenamewithoutext}.funscript"
|
||||
funscriptnewlocaton = os.path.join(filepath, funscriptnewname)
|
||||
|
||||
shutil.copy2(funscriptfile, funscriptnewlocaton)
|
||||
|
||||
log.info(f"Copy {funscriptfile} to {funscriptnewlocaton}")
|
||||
# log.info(filename)
|
||||
# log.info(filenamewithoutext)
|
||||
|
||||
|
||||
def convert_lovense_to_funscript(sceneinfo, patternfile, funscriptfile):
|
||||
|
||||
# Sceneninfo
|
||||
title = re.sub(r"\[PDT: .+?\]\s+", "", sceneinfo["title"])
|
||||
duration = int(sceneinfo["files"][0]["duration"] + 0.5) * 1000
|
||||
|
||||
# Lovensescript
|
||||
with open(patternfile, "r") as losc:
|
||||
lovensactions = json.load(losc)
|
||||
|
||||
# Funscript-Output
|
||||
data = {}
|
||||
data["version"] = "1.0"
|
||||
data["range"] = 100
|
||||
data["inverted"] = False
|
||||
data["metadata"] = {}
|
||||
data["metadata"]["bookmarks"] = {}
|
||||
data["metadata"]["chapters"] = {}
|
||||
data["metadata"]["performers"] = {}
|
||||
data["metadata"]["tags"] = {}
|
||||
data["metadata"]["title"] = title
|
||||
data["metadata"]["creator"] = "Adulttime Interactive Downloader for Stash"
|
||||
data["metadata"]["description"] = ""
|
||||
data["metadata"]["duration"] = duration
|
||||
data["metadata"]["license"] = "Open"
|
||||
data["metadata"]["script_url"] = ""
|
||||
data["metadata"]["type"] = "basic"
|
||||
data["metadata"]["video_url"] = ""
|
||||
data["metadata"]["notes"] = "Convert from Lovense to Funscript"
|
||||
data["actions"] = []
|
||||
|
||||
marker_at = 0
|
||||
marker_pos = 0
|
||||
for la in lovensactions:
|
||||
|
||||
# 0 nicht konvertieren
|
||||
if la["v"] == 0:
|
||||
marker_at = 0
|
||||
else:
|
||||
marker_at = la["v"] * FAKTORCONV
|
||||
|
||||
# Division durch 0 nicht moeglich
|
||||
if la["t"] == 0:
|
||||
print("Skip Junk with Value '%s' " % la["t"])
|
||||
else:
|
||||
# marker_pos = (la["t"] / 1000)*1
|
||||
marker_pos = (la["t"]) * 1
|
||||
data["actions"].extend(
|
||||
[{"pos": int(marker_at + 0.5), "at": int(marker_pos + 0.5)}]
|
||||
)
|
||||
|
||||
# json_data = json.dumps(data)
|
||||
# log.debug(json_data)
|
||||
|
||||
# Funscript schreiben
|
||||
open(funscriptfile, "w+").write(json.dumps(data))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
22
plugins/AdulttimeInteractiveDL/AdulttimeInteractiveDL.yml
Normal file
22
plugins/AdulttimeInteractiveDL/AdulttimeInteractiveDL.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
name: "Adulttime Interactive Downloader"
|
||||
description: Download Interactive Files for Adulttime Scenes
|
||||
version: 0.1.1
|
||||
url: https://github.com/tooliload/StashAppCommunityScripts/tree/main/plugins/AdulttimeInteractiveDL
|
||||
exec:
|
||||
- python
|
||||
- "{pluginDir}/AdulttimeInteractiveDL.py"
|
||||
interface: raw
|
||||
tasks:
|
||||
- name: "Download"
|
||||
description: "Download Interactive Files from Adulttime Scenes"
|
||||
defaultArgs:
|
||||
mode: download
|
||||
- name: "Clear Cache"
|
||||
description: "Clean cached JSON Answers and Interactive Cache"
|
||||
defaultArgs:
|
||||
mode: cacheclean
|
||||
hooks:
|
||||
- name: download
|
||||
description: Try download if Scene updated
|
||||
triggeredBy:
|
||||
- Scene.Update.Post
|
||||
1
plugins/AdulttimeInteractiveDL/requirements.txt
Normal file
1
plugins/AdulttimeInteractiveDL/requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
stashapp-tools>=0.2.33
|
||||
70
plugins/PythonToolsInstaller/PythonToolsInstaller.py
Normal file
70
plugins/PythonToolsInstaller/PythonToolsInstaller.py
Normal file
@@ -0,0 +1,70 @@
|
||||
import requests, os, shutil
|
||||
import re, sys, json, time, sysconfig
|
||||
from inspect import getmembers, isfunction
|
||||
from venv import create
|
||||
from os.path import join, expanduser, abspath
|
||||
import subprocess
|
||||
import shutil
|
||||
|
||||
def main():
|
||||
input = None
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
input = readJSONInput()
|
||||
|
||||
output = {}
|
||||
run(input, output)
|
||||
|
||||
out = json.dumps(output)
|
||||
print(out + "\n")
|
||||
|
||||
def readJSONInput():
|
||||
input = sys.stdin.read()
|
||||
return json.loads(input)
|
||||
|
||||
|
||||
def run(input, output):
|
||||
|
||||
if input == "None" or input == "":
|
||||
return
|
||||
|
||||
|
||||
PLUGIN_DIR = input["server_connection"]["PluginDir"]
|
||||
modeArg = input['args']["mode"]
|
||||
|
||||
try:
|
||||
if modeArg == "" or modeArg == "add":
|
||||
return
|
||||
|
||||
elif modeArg == "process_py_stashapi_tools":
|
||||
get_download_py_stashapp_tools(PLUGIN_DIR)
|
||||
|
||||
except Exception as e:
|
||||
raise
|
||||
output["error"] = str(e)
|
||||
return
|
||||
|
||||
output["output"] = "ok"
|
||||
|
||||
def get_download_py_stashapp_tools(PLUGIN_DIR):
|
||||
|
||||
org_packagedir = sysconfig.get_paths()["purelib"] # /usr/lib/python3.11/site-packages/usr/lib/python3.11/site-packages
|
||||
|
||||
used_dir = f"{PLUGIN_DIR}"
|
||||
create(f"{used_dir}/venv/", with_pip=True)
|
||||
|
||||
# where requirements.txt is in same dir as this script
|
||||
subprocess.run([f"{used_dir}/venv/bin/pip", "install", "-r", abspath(f"{used_dir}/packages/stashtools.txt")],stdout=None)
|
||||
|
||||
# venv/lib/python3.11/site-packages/stashapp_tools-
|
||||
|
||||
src = f"{used_dir}/venv/lib/python3.11/site-packages"
|
||||
destination = shutil.copytree(src, org_packagedir,ignore_func,None,shutil.copy2,False,True)
|
||||
fp = open(f'{used_dir}/copydo.txt', 'w+')
|
||||
fp.write("%s\n" % print(destination))
|
||||
|
||||
def ignore_func(src, names):
|
||||
return ['env'] if 'env' in names else []
|
||||
|
||||
|
||||
main()
|
||||
13
plugins/PythonToolsInstaller/PythonToolsInstaller.yml
Normal file
13
plugins/PythonToolsInstaller/PythonToolsInstaller.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
name: "Python Tools Installer"
|
||||
description: Download stashapp-tools for DockerEnv
|
||||
version: 0.1.
|
||||
url: https://github.com/tooliload/StashAppCommunityScripts/tree/main/plugins/PythonToolsInstaller
|
||||
exec:
|
||||
- python
|
||||
- "{pluginDir}/PythonToolsInstaller.py"
|
||||
interface: raw
|
||||
tasks:
|
||||
- name: "Install"
|
||||
description: Install Python Module stashapi-tools
|
||||
defaultArgs:
|
||||
mode: process_py_stashapi_tools
|
||||
1
plugins/PythonToolsInstaller/packages/stashtools.txt
Normal file
1
plugins/PythonToolsInstaller/packages/stashtools.txt
Normal file
@@ -0,0 +1 @@
|
||||
stashapp-tools
|
||||
Reference in New Issue
Block a user