Initial commit

This commit is contained in:
sqozz 2023-02-23 11:29:44 +01:00
commit 611d7ad39f
5 changed files with 283 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
config.ini

0
README.md Normal file
View file

12
config.ini Normal file
View file

@ -0,0 +1,12 @@
[taiga]
url = https://taiga.example.com
username = taigauser@example.com
password = mysupersecretpassword
project_slug = 3d-printing
userstory_use_custom_field = True
userstory_custom_field_name = Platform link
initial_task_status = New

268
importer.py Normal file
View file

@ -0,0 +1,268 @@
import os
import uuid
import tempfile
import requests
import configparser
import urllib.parse
from taiga import TaigaAPI
# Config parsing
CONFIG=configparser.ConfigParser()
CONFIG.read("config.ini")
# Static variables for scrape requests to printables.com
UUID=str(uuid.uuid4())
ENDPOINT_URL="https://api.printables.com/graphql/"
HEADERS = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0",
"Accept": "application/json, text/plain, */*",
"Accept-Language": "en",
"Content-Type": "application/json",
"Referer": "https://www.printables.com/",
"operation": "PrintProfile",
"apollographql-client-version": "v2.46.2",
"Client-Uid": UUID,
"Origin": "https://www.printables.com",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-site",
"Authorization": "",
"Connection": "keep-alive"
}
def get_printables_print_data(model_id):
PARAMS = '{"operationName":"PrintProfile","variables":{"id":"' + str(model_id) + '''"},"query":"query PrintProfile($id: ID!) {
print(id: $id) {
...PrintDetailFragment
__typename
}
}
fragment PrintDetailFragment on PrintType {
id
slug
name
authorship
description
hasModel
summary
printDuration
numPieces
weight
nozzleDiameters
usedMaterial
layerHeights
materials {
id
name
__typename
}
filesCount
pdfFilePath
userGcodeCount
printer {
id
name
__typename
}
images {
...ImageSimpleFragment
__typename
}
tags {
name
id
__typename
}
thingiverseLink
filesType
foundInUserGcodes
remixParents {
...remixParentDetail
__typename
}
gcodes {
id
name
filePath
fileSize
filePreviewPath
__typename
}
stls {
id
name
filePath
fileSize
filePreviewPath
__typename
}
slas {
id
name
filePath
fileSize
filePreviewPath
__typename
}
...LatestCompetitionResult
competitions {
id
name
slug
description
isOpened
__typename
}
competitionResults {
placement
competition {
id
name
slug
printsCount
openedFrom
openedTo
__typename
}
__typename
}
__typename
}
fragment ImageSimpleFragment on PrintImageType {
id
filePath
rotation
__typename
}
fragment remixParentDetail on PrintRemixType {
id
parentPrintId
parentPrintName
parentPrintAuthor {
id
slug
publicUsername
company
verified
handle
__typename
}
parentPrint {
id
name
slug
datePublished
images {
...ImageSimpleFragment
__typename
}
license {
id
name
disallowRemixing
__typename
}
eduProject {
id
__typename
}
__typename
}
url
urlAuthor
urlImage
urlTitle
__typename
}
fragment LatestCompetitionResult on PrintType {
latestCompetitionResult {
placement
competitionId
__typename
}
__typename
}"}'''
PARAMS=PARAMS.replace("\n", "\\n")
req = requests.post(ENDPOINT_URL, headers=HEADERS, data=PARAMS)
print_data = req.json()["data"]["print"]
return print_data
def get_modelid_from_url(url):
parsed_url = urllib.parse.urlparse(url)
path = parsed_url.path
path_components = path.split("/")
path_components = list(filter(lambda x: x != "", path_components)) #filter empty elements
if path_components[0] != "model":
raise Exception("Only direct links to models are supported")
model_slug = path_components[1]
model_id = model_slug.split("-")[0]
return model_id
link = input("Please paste link: ")
model_id = get_modelid_from_url(link)
print_data = get_printables_print_data(model_id)
api = TaigaAPI(host=CONFIG["taiga"]["url"])
api.auth(
username=CONFIG["taiga"]["username"],
password=CONFIG["taiga"]["password"]
)
proj = api.projects.get_by_slug(CONFIG["taiga"]["project_slug"])
# Create userstory for printable
story = proj.add_user_story(
print_data["name"],
description = print_data["description"],
tags = list(map(lambda x: x.get("name"), print_data["tags"])))
# Set custom field for platform link if enabled and configured
if bool(CONFIG["taiga"]["userstory_use_custom_field"]):
us_attributes = list(map(lambda x: {"id": x.id, "name": x.name}, api.user_story_attributes.list()))
attribute_id = list(filter(lambda x: CONFIG["taiga"]["userstory_custom_field_name"] in x["name"], us_attributes))[0]["id"]
story.set_attribute(attribute_id, link)
# Find id for desired status of newly tasks
task_statuses = list(map(lambda x: {"id": x.id, "name": x.name}, api.task_statuses.list()))
task_status_id = list(filter(lambda x: CONFIG["taiga"]["initial_task_status"] == x["name"], task_statuses))[0]["id"]
tmpdir = tempfile.TemporaryDirectory() #workdir for downloads
imagepath = print_data["images"][0]["filePath"]
imageurl = urllib.parse.urljoin("https://media.printables.com", imagepath)
local_file = os.path.join(tmpdir.name, os.path.basename(imagepath))
print("Downloading first image of printable to {}".format(local_file), end="")
with requests.get(imageurl, stream=True) as r:
r.raise_for_status()
with open(local_file, "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
print(" done.")
story.attach(local_file)
stls = list(filter(lambda x: x["filePath"].endswith(".stl"), print_data["stls"]))
stl_files = list(map(lambda x: {"name": x["name"], "filePath": x["filePath"]},stls))
for stl_file in stl_files:
stlpath = stl_file["filePath"]
filename = os.path.basename(stlpath)
print("Creating task for file {}".format(filename), end="")
task = story.add_task(filename, task_status_id)
stlurl = urllib.parse.urljoin("https://files.printables.com", stlpath)
local_file = os.path.join(tmpdir.name, filename)
with requests.get(stlurl, stream=True) as r:
r.raise_for_status()
with open(local_file, "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
task.attach(local_file)
print(" done.")
newstory_url= urllib.parse.urljoin(CONFIG["taiga"]["url"], os.path.join("project", CONFIG["taiga"]["project_slug"], "us", str(story.ref)))
print("New story created at: {}".format(newstory_url))

2
requirements.txt Normal file
View file

@ -0,0 +1,2 @@
python-taiga
requests