| import os |
| import threading |
| import subprocess |
| import requests |
| import time |
| from flask import Flask, render_template, request, jsonify |
|
|
| app = Flask(__name__) |
|
|
| |
| HOME_DIR = os.path.expanduser('~') |
| BASE_PICTURES = os.path.join(HOME_DIR, 'Pictures') |
|
|
| |
| status_data = { |
| 'text': 'Siap...', |
| 'percent': 0, |
| 'status': 'idle' |
| } |
|
|
| |
| @app.route('/scan', methods=['POST']) |
| def scan_url(): |
| raw_url = request.json.get('url') |
| if not raw_url: return jsonify({'status': 'error', 'message': 'URL kosong'}) |
|
|
| |
| if "tiktok.com" in raw_url: |
| return jsonify({ |
| 'status': 'success', |
| 'mode': 'bulk_tiktok', |
| 'message': 'TikTok Slide Terdeteksi (Mode API)' |
| }) |
|
|
| |
| try: |
| command = ["gallery-dl", "-g", "--cookies-from-browser", "brave", raw_url] |
| result = subprocess.run(command, capture_output=True, text=True) |
|
|
| if result.returncode == 0: |
| raw_links = result.stdout.strip().split('\n') |
| valid_links = [link for link in raw_links if link.startswith('http')] |
| if not valid_links: |
| return jsonify({'status': 'error', 'message': 'Tidak ada gambar ditemukan.'}) |
| return jsonify({ |
| 'status': 'success', |
| 'mode': 'select_ig', |
| 'images': valid_links, |
| 'count': len(valid_links) |
| }) |
| else: |
| return jsonify({'status': 'error', 'message': "Gagal Scan IG (Cek Login Brave)"}) |
|
|
| except Exception as e: |
| return jsonify({'status': 'error', 'message': str(e)}) |
|
|
|
|
| |
| def run_tiktok_api(url): |
| global status_data |
| status_data['status'] = 'downloading' |
|
|
| TARGET_FOLDER = os.path.join(BASE_PICTURES, 'TikTok') |
| if not os.path.exists(TARGET_FOLDER): os.makedirs(TARGET_FOLDER) |
|
|
| try: |
| status_data['percent'] = 10 |
| status_data['text'] = "Menghubungi Server TikWM..." |
|
|
| |
| |
| api_url = "https://www.tikwm.com/api/" |
| payload = {'url': url, 'hd': 1} |
|
|
| req = requests.post(api_url, data=payload) |
| resp = req.json() |
|
|
| image_urls = [] |
|
|
| |
| if resp.get('code') == 0: |
| data = resp.get('data', {}) |
| if 'images' in data: |
| image_urls = data['images'] |
| else: |
| |
| if 'cover' in data: image_urls.append(data['cover']) |
| else: |
| raise Exception("Gagal mengambil data dari API (Link Private/Salah).") |
|
|
| if not image_urls: |
| raise Exception("Tidak ada gambar ditemukan.") |
|
|
| |
| total = len(image_urls) |
| print(f"API Berhasil: Ditemukan {total} slide.") |
|
|
| |
| headers = { |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" |
| } |
|
|
| success_count = 0 |
| for i, img_url in enumerate(image_urls): |
| current = i + 1 |
| status_data['percent'] = (current / total) * 100 |
| status_data['text'] = f"Menyimpan Slide {current} dari {total}..." |
|
|
| try: |
| response = requests.get(img_url, headers=headers, stream=True) |
| if response.status_code == 200: |
| filename = f"TK_{int(time.time())}_{current}.jpg" |
| full_path = os.path.join(TARGET_FOLDER, filename) |
|
|
| with open(full_path, 'wb') as f: |
| for chunk in response.iter_content(1024): |
| f.write(chunk) |
| success_count += 1 |
| except: pass |
|
|
| status_data['status'] = 'finished' |
| status_data['percent'] = 100 |
| status_data['text'] = f"Selesai! {success_count} slide tersimpan." |
|
|
| except Exception as e: |
| print(f"Error TikTok API: {e}") |
| status_data['status'] = 'error' |
| status_data['text'] = "Gagal memproses (Server API sibuk/Link salah)" |
|
|
|
|
| |
| def run_ig_manual(selected_urls): |
| global status_data |
| status_data['status'] = 'downloading' |
| total = len(selected_urls) |
| TARGET_FOLDER = os.path.join(BASE_PICTURES, 'Instagram') |
| if not os.path.exists(TARGET_FOLDER): os.makedirs(TARGET_FOLDER) |
|
|
| headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"} |
|
|
| for i, img_url in enumerate(selected_urls): |
| try: |
| current = i + 1 |
| status_data['percent'] = (current / total) * 100 |
| status_data['text'] = f"Menyimpan ke Instagram ({current}/{total})..." |
| response = requests.get(img_url, headers=headers, stream=True) |
| if response.status_code == 200: |
| filename = f"IG_{int(time.time())}_{current}.jpg" |
| full_path = os.path.join(TARGET_FOLDER, filename) |
| with open(full_path, 'wb') as f: |
| for chunk in response.iter_content(1024): |
| f.write(chunk) |
| except: pass |
|
|
| status_data['status'] = 'finished' |
| status_data['percent'] = 100 |
| status_data['text'] = "Selesai! Cek folder Pictures/Instagram" |
|
|
|
|
| @app.route('/') |
| def home(): |
| return render_template('index.html') |
|
|
| @app.route('/action', methods=['POST']) |
| def action(): |
| data = request.json |
| mode = data.get('mode') |
|
|
| if mode == 'tiktok': |
| url = data.get('url') |
| t = threading.Thread(target=run_tiktok_api, args=(url,)) |
| t.start() |
| elif mode == 'instagram': |
| urls = data.get('urls') |
| t = threading.Thread(target=run_ig_manual, args=(urls,)) |
| t.start() |
|
|
| return jsonify({'status': 'started'}) |
|
|
| @app.route('/status') |
| def status(): |
| return jsonify(status_data) |
|
|
| if __name__ == '__main__': |
| app.run(debug=True, port=5001, host='0.0.0.0') |
|
|