Sabun76 commited on
Commit
b5760be
·
verified ·
1 Parent(s): 9821366

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +185 -0
app.py ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import threading
3
+ import subprocess
4
+ import requests
5
+ import time
6
+ from flask import Flask, render_template, request, jsonify
7
+
8
+ app = Flask(__name__)
9
+
10
+ # Lokasi Dasar
11
+ HOME_DIR = os.path.expanduser('~')
12
+ BASE_PICTURES = os.path.join(HOME_DIR, 'Pictures')
13
+
14
+ # Status Global
15
+ status_data = {
16
+ 'text': 'Siap...',
17
+ 'percent': 0,
18
+ 'status': 'idle'
19
+ }
20
+
21
+ # --- SCAN URL ---
22
+ @app.route('/scan', methods=['POST'])
23
+ def scan_url():
24
+ raw_url = request.json.get('url')
25
+ if not raw_url: return jsonify({'status': 'error', 'message': 'URL kosong'})
26
+
27
+ # TIKTOK: Bypass Preview
28
+ if "tiktok.com" in raw_url:
29
+ return jsonify({
30
+ 'status': 'success',
31
+ 'mode': 'bulk_tiktok',
32
+ 'message': 'TikTok Slide Terdeteksi (Mode API)'
33
+ })
34
+
35
+ # INSTAGRAM: Pakai Gallery-DL
36
+ try:
37
+ command = ["gallery-dl", "-g", "--cookies-from-browser", "brave", raw_url]
38
+ result = subprocess.run(command, capture_output=True, text=True)
39
+
40
+ if result.returncode == 0:
41
+ raw_links = result.stdout.strip().split('\n')
42
+ valid_links = [link for link in raw_links if link.startswith('http')]
43
+ if not valid_links:
44
+ return jsonify({'status': 'error', 'message': 'Tidak ada gambar ditemukan.'})
45
+ return jsonify({
46
+ 'status': 'success',
47
+ 'mode': 'select_ig',
48
+ 'images': valid_links,
49
+ 'count': len(valid_links)
50
+ })
51
+ else:
52
+ return jsonify({'status': 'error', 'message': "Gagal Scan IG (Cek Login Brave)"})
53
+
54
+ except Exception as e:
55
+ return jsonify({'status': 'error', 'message': str(e)})
56
+
57
+
58
+ # --- EKSEKUTOR TIKTOK (JALUR BELAKANG / API) ---
59
+ def run_tiktok_api(url):
60
+ global status_data
61
+ status_data['status'] = 'downloading'
62
+
63
+ TARGET_FOLDER = os.path.join(BASE_PICTURES, 'TikTok')
64
+ if not os.path.exists(TARGET_FOLDER): os.makedirs(TARGET_FOLDER)
65
+
66
+ try:
67
+ status_data['percent'] = 10
68
+ status_data['text'] = "Menghubungi Server TikWM..."
69
+
70
+ # 1. TEMBAK KE API PUBLIK (TikWM)
71
+ # Ini akan mengembalikan JSON berisi link gambar yang bersih
72
+ api_url = "https://www.tikwm.com/api/"
73
+ payload = {'url': url, 'hd': 1}
74
+
75
+ req = requests.post(api_url, data=payload)
76
+ resp = req.json()
77
+
78
+ image_urls = []
79
+
80
+ # 2. AMBIL LIST GAMBAR DARI RESPON
81
+ if resp.get('code') == 0:
82
+ data = resp.get('data', {})
83
+ if 'images' in data:
84
+ image_urls = data['images']
85
+ else:
86
+ # Kalau ternyata bukan slide, tapi video single (ambil covernya)
87
+ if 'cover' in data: image_urls.append(data['cover'])
88
+ else:
89
+ raise Exception("Gagal mengambil data dari API (Link Private/Salah).")
90
+
91
+ if not image_urls:
92
+ raise Exception("Tidak ada gambar ditemukan.")
93
+
94
+ # 3. DOWNLOAD MANUAL
95
+ total = len(image_urls)
96
+ print(f"API Berhasil: Ditemukan {total} slide.")
97
+
98
+ # Headers standar
99
+ headers = {
100
+ "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"
101
+ }
102
+
103
+ success_count = 0
104
+ for i, img_url in enumerate(image_urls):
105
+ current = i + 1
106
+ status_data['percent'] = (current / total) * 100
107
+ status_data['text'] = f"Menyimpan Slide {current} dari {total}..."
108
+
109
+ try:
110
+ response = requests.get(img_url, headers=headers, stream=True)
111
+ if response.status_code == 200:
112
+ filename = f"TK_{int(time.time())}_{current}.jpg"
113
+ full_path = os.path.join(TARGET_FOLDER, filename)
114
+
115
+ with open(full_path, 'wb') as f:
116
+ for chunk in response.iter_content(1024):
117
+ f.write(chunk)
118
+ success_count += 1
119
+ except: pass
120
+
121
+ status_data['status'] = 'finished'
122
+ status_data['percent'] = 100
123
+ status_data['text'] = f"Selesai! {success_count} slide tersimpan."
124
+
125
+ except Exception as e:
126
+ print(f"Error TikTok API: {e}")
127
+ status_data['status'] = 'error'
128
+ status_data['text'] = "Gagal memproses (Server API sibuk/Link salah)"
129
+
130
+
131
+ # --- EKSEKUTOR IG ---
132
+ def run_ig_manual(selected_urls):
133
+ global status_data
134
+ status_data['status'] = 'downloading'
135
+ total = len(selected_urls)
136
+ TARGET_FOLDER = os.path.join(BASE_PICTURES, 'Instagram')
137
+ if not os.path.exists(TARGET_FOLDER): os.makedirs(TARGET_FOLDER)
138
+
139
+ 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"}
140
+
141
+ for i, img_url in enumerate(selected_urls):
142
+ try:
143
+ current = i + 1
144
+ status_data['percent'] = (current / total) * 100
145
+ status_data['text'] = f"Menyimpan ke Instagram ({current}/{total})..."
146
+ response = requests.get(img_url, headers=headers, stream=True)
147
+ if response.status_code == 200:
148
+ filename = f"IG_{int(time.time())}_{current}.jpg"
149
+ full_path = os.path.join(TARGET_FOLDER, filename)
150
+ with open(full_path, 'wb') as f:
151
+ for chunk in response.iter_content(1024):
152
+ f.write(chunk)
153
+ except: pass
154
+
155
+ status_data['status'] = 'finished'
156
+ status_data['percent'] = 100
157
+ status_data['text'] = "Selesai! Cek folder Pictures/Instagram"
158
+
159
+
160
+ @app.route('/')
161
+ def home():
162
+ return render_template('index.html')
163
+
164
+ @app.route('/action', methods=['POST'])
165
+ def action():
166
+ data = request.json
167
+ mode = data.get('mode')
168
+
169
+ if mode == 'tiktok':
170
+ url = data.get('url')
171
+ t = threading.Thread(target=run_tiktok_api, args=(url,))
172
+ t.start()
173
+ elif mode == 'instagram':
174
+ urls = data.get('urls')
175
+ t = threading.Thread(target=run_ig_manual, args=(urls,))
176
+ t.start()
177
+
178
+ return jsonify({'status': 'started'})
179
+
180
+ @app.route('/status')
181
+ def status():
182
+ return jsonify(status_data)
183
+
184
+ if __name__ == '__main__':
185
+ app.run(debug=True, port=5001, host='0.0.0.0')