Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dist-ssr
*.njsproj
*.sln
*.sw?
*.code-workspace

# Virtual Environments
.venv
Expand Down
2 changes: 1 addition & 1 deletion backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ def import_model_by_id(payload: dict):
# we only save stl for now
ext = typeName if typeName is not None else ".stl"

filename = f"{mid}{ext}"
filename = f"{mid}.{ext}"
path = os.path.join(UPLOAD_DIR, filename)

# Check if url is not None before calling importer
Expand Down
90 changes: 54 additions & 36 deletions backend/importers/printables.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import base64



MODELQUERY = """
query ModelFiles($id: ID!) {
model: print(id: $id) {
Expand Down Expand Up @@ -137,13 +136,14 @@
}
"""

class PrintablesImporter():
'''Handles the import from printables site
'''

class PrintablesImporter:
"""Handles the import from printables site"""

def __init__(self):
self.session: requests.Session
self.graphurl = "https://api.printables.com/graphql/"
self.clientId= ""
self.clientId = ""
self.fileResult: bool
self.fileDownloadLink = ""

Expand All @@ -160,15 +160,15 @@ def _set_client_data(self, url):
if response.status_code != 200:
return response.status_code

self.clientId = re.search("data-client-uid=\"(([a-z0-9-])+)", response.text)[1]
self.clientId = re.search('data-client-uid="(([a-z0-9-])+)', response.text)[1]

return True

def _get_model_info(self, modelId):
header = {
"accept": "application/graphql-response+json, application/graphql+json, application/json, text/event-stream, multipart/mixed",
"accept-language": "en",
"client-uid" : self.clientId,
"client-uid": self.clientId,
"cache-control": "no-cache",
"content-type": "application/json",
"graphql-client-version": "v3.0.11",
Expand All @@ -178,83 +178,101 @@ def _get_model_info(self, modelId):
}
variables = {"id": modelId}

response = self.session.post(self.graphurl, json={'query': MODELQUERY , 'variables': variables}, headers=header)
response = self.session.post(
self.graphurl,
json={"query": MODELQUERY, "variables": variables},
headers=header,
)

if response.status_code != 200:
return response.status_code

modelData = response.json()
modelCollection = []
try:
for model in modelData["data"]["model"]["stls"]:
modelCollection.append(
{
"parentId": modelId,
"id": model["id"],
"name": model["name"],
"folder": model["folder"],
"previewPath": "https://files.printables.com/" + model["filePreviewPath"],
"typeName": model["name"].split(".")[-1],
}
{
"parentId": modelId,
"id": model["id"],
"name": model["name"],
"folder": model["folder"],
"previewPath": "https://files.printables.com/"
+ model["filePreviewPath"],
"typeName": model["name"].split(".")[-1],
}
)
return modelCollection
except Exception as e:
raise e

def _get_file(self, modelId, parentId):
header = {
"accept": "application/graphql-response+json, application/graphql+json, application/json, text/event-stream, multipart/mixed",
"accept-language": "en",
"client-uid" : self.clientId,
"client-uid": self.clientId,
"cache-control": "no-cache",
"content-type": "application/json",
"graphql-client-version": "v3.0.11",
"pragma": "no-cache",
"priority": "u=1, i",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
}
variables = {"fileType":"stl","id":modelId,"modelId":parentId,"source":"model_detail"}
variables = {
"fileType": "stl",
"id": modelId,
"modelId": parentId,
"source": "model_detail",
}

response = self.session.post(self.graphurl, json={'query': FILEQUERY , 'variables': variables}, headers=header)
response = self.session.post(
self.graphurl,
json={"query": FILEQUERY, "variables": variables},
headers=header,
)
if response.status_code != 200:
return None
fileData = response.json()
try:
self.fileResult = fileData["data"]["getDownloadLink"]["ok"]
self.fileDownloadLink = fileData["data"]["getDownloadLink"]["output"]["link"]
self.fileDownloadLink = fileData["data"]["getDownloadLink"]["output"][
"link"
]
except Exception as e:
raise e

if self.fileResult is True:
fileheader = {
"accept": "application/graphql-response+json, application/graphql+json, application/json, text/event-stream, multipart/mixed",
"accept-language": "en",
"client-uid" : self.clientId,
"client-uid": self.clientId,
"cache-control": "no-cache",
"pragma": "no-cache",
"priority": "u=1, i",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
}
file = self.session.get(self.fileDownloadLink, allow_redirects=True, headers=fileheader)
file = self.session.get(
self.fileDownloadLink, allow_redirects=True, headers=fileheader
)
return file

def _make_thumbnail(self, url):
if len(url) > 5:
fileheader = {
"accept": "image/*, application/json, text/event-stream, multipart/mixed",
"accept-language": "en",
"client-uid" : self.clientId,
"cache-control": "no-cache",
"pragma": "no-cache",
"priority": "u=1, i",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
"accept": "image/*, application/json, text/event-stream, multipart/mixed",
"accept-language": "en",
"client-uid": self.clientId,
"cache-control": "no-cache",
"pragma": "no-cache",
"priority": "u=1, i",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
}
file = self.session.get(url, allow_redirects=True, headers=fileheader)
encoded_string = base64.b64encode(file.content)
return "data:image/png;base64," + encoded_string.decode()

return ""

def importfromId(self, modelId, parentId, previewPath):
self.session = requests.Session()
try:
Expand Down Expand Up @@ -282,4 +300,4 @@ def getModelOptions(self, url):
except Exception as e:
raise e
finally:
self.session.close()
self.session.close()
22 changes: 21 additions & 1 deletion frontend/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,26 @@ const App = () => {
setSelectedOptions(newSet);
};

const handleUpdateSTEPThumbnail = async (newModel: STLModel) => {
let tbuff = await fetch(port + newModel.url).then((response) => {
return response;
});
let thumbnailBuffer = await tbuff.bytes().then((bytes) => {
return bytes;
});
try {
let thumbnail = await generateThumbnail(
new File([thumbnailBuffer], newModel.name),
);
let newerModel = await api.updateModel(newModel.id, {
thumbnail: thumbnail,
});
setModels((prev) => [newerModel, ...prev]);
} catch (e) {
console.warn("Thumbnail generation failed, uploading without thumbnail");
}
};

const handleImportChoice = async () => {
if (!importUrl || !importFolderId) return;

Expand All @@ -357,8 +377,8 @@ const App = () => {
importFolderId,
model.typeName,
);
await handleUpdateSTEPThumbnail(newModel);
setUploadQueue((prev) => prev - 1);
setModels((prev) => [newModel, ...prev]);
}
}
} catch (error) {
Expand Down