| from flask import Flask, request, send_file, jsonify, make_response |
| import subprocess, os, shutil, uuid |
|
|
| app = Flask(__name__) |
|
|
| def cors(response): |
| response.headers['Access-Control-Allow-Origin'] = '*' |
| response.headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS' |
| response.headers['Access-Control-Allow-Headers'] = 'Content-Type' |
| return response |
|
|
| @app.before_request |
| def handle_options(): |
| if request.method == 'OPTIONS': |
| return cors(make_response('', 200)) |
|
|
| @app.after_request |
| def after(response): |
| return cors(response) |
|
|
| @app.route("/", methods=["GET"]) |
| def index(): |
| return jsonify({"status": "HtStudio Python Builder 🚀 (APK + EXE)"}) |
|
|
| def make_py_html(py_code, app_name): |
| escaped = py_code.replace('\\','\\\\').replace('`','\\`').replace('$','\\$') |
| return f"""<!DOCTYPE html><html><head><meta charset="UTF-8"><title>{app_name}</title> |
| <script src="https://skulpt.org/js/skulpt.min.js"></script> |
| <script src="https://skulpt.org/js/skulpt-stdlib.js"></script> |
| <style>body{{margin:0;background:#1e1e2e;color:#cdd6f4;font-family:monospace;padding:16px;}} |
| #output{{white-space:pre-wrap;font-size:14px;line-height:1.6;}}.err{{color:#f38ba8;}}</style> |
| </head><body><div id="output"></div> |
| <script> |
| var code=`{escaped}`; |
| function outf(t){{document.getElementById('output').innerHTML+=t;}} |
| function builtinRead(x){{if(Sk.builtinFiles===undefined||Sk.builtinFiles["files"][x]===undefined)throw "File not found: '"+x+"'";return Sk.builtinFiles["files"][x];}} |
| Sk.configure({{output:outf,read:builtinRead}}); |
| Sk.misceval.asyncToPromise(()=>Sk.importMainWithBody("<stdin>",false,code,true)) |
| .catch(e=>{{var el=document.createElement('div');el.className='err';el.textContent='Hata: '+e.toString();document.getElementById('output').appendChild(el);}}); |
| </script></body></html>""" |
|
|
| @app.route("/build-python", methods=["POST"]) |
| def build_python_apk(): |
| data = request.get_json(force=True) |
| py_code = data.get("code", "") |
| app_name = data.get("name", "HtApp").strip().replace(" ", "_") |
| pkg_name = data.get("pkg", "com.htstudio.app").strip() |
| if not py_code.strip(): |
| return jsonify({"error": "Python kodu boş"}), 400 |
| job_id = str(uuid.uuid4())[:8] |
| work_dir = f"/tmp/build_py_{job_id}" |
| os.makedirs(work_dir, exist_ok=True) |
| try: |
| with open(f"{work_dir}/index.html", "w", encoding="utf-8") as f: |
| f.write(make_py_html(py_code, app_name)) |
| result = subprocess.run( |
| ["bash", "/app/build_apk.sh", work_dir, app_name, pkg_name, "/opt/debug.keystore"], |
| stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, timeout=120 |
| ) |
| if result.returncode != 0: |
| return jsonify({"error": "Python APK başarısız", "log": result.stdout[-3000:]}), 500 |
| apk_path = f"{work_dir}/output.apk" |
| if not os.path.exists(apk_path): |
| return jsonify({"error": "APK oluşturulamadı", "log": result.stdout[-3000:]}), 500 |
| return send_file(apk_path, as_attachment=True, |
| download_name=f"{app_name}_HtStudio.apk", |
| mimetype="application/vnd.android.package-archive") |
| finally: |
| shutil.rmtree(work_dir, ignore_errors=True) |
|
|
| @app.route("/build-python-exe", methods=["POST"]) |
| def build_python_exe(): |
| data = request.get_json(force=True) |
| py_code = data.get("code", "") |
| app_name = data.get("name", "HtApp").strip().replace(" ", "_") |
| pkg_name = data.get("pkg", "com.htstudio.app").strip() |
| if not py_code.strip(): |
| return jsonify({"error": "Python kodu boş"}), 400 |
| job_id = str(uuid.uuid4())[:8] |
| work_dir = f"/tmp/build_pyexe_{job_id}" |
| os.makedirs(work_dir, exist_ok=True) |
| try: |
| with open(f"{work_dir}/index.html", "w", encoding="utf-8") as f: |
| f.write(make_py_html(py_code, app_name)) |
| result = subprocess.run( |
| ["bash", "/app/build_exe.sh", work_dir, app_name, pkg_name], |
| stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, timeout=300 |
| ) |
| if result.returncode != 0: |
| return jsonify({"error": "Python EXE başarısız", "log": result.stdout[-3000:]}), 500 |
| exe_path = f"{work_dir}/output.exe" |
| if not os.path.exists(exe_path): |
| return jsonify({"error": "EXE oluşturulamadı", "log": result.stdout[-3000:]}), 500 |
| return send_file(exe_path, as_attachment=True, |
| download_name=f"{app_name}_HtStudio.exe", |
| mimetype="application/octet-stream") |
| finally: |
| shutil.rmtree(work_dir, ignore_errors=True) |
|
|
| if __name__ == "__main__": |
| app.run(host="0.0.0.0", port=7860) |
|
|