Update app.py
Browse files
app.py
CHANGED
@@ -1,45 +1,216 @@
|
|
1 |
-
from flask import Flask, request,
|
2 |
-
import
|
|
|
|
|
|
|
|
|
3 |
|
4 |
app = Flask(__name__)
|
|
|
|
|
5 |
|
6 |
-
#
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
|
15 |
@app.route('/')
|
16 |
-
def
|
17 |
-
|
18 |
-
return html_form
|
19 |
|
20 |
-
@app.route('/
|
21 |
-
def
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
|
27 |
-
|
28 |
-
|
29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
|
36 |
-
|
37 |
-
|
|
|
|
|
|
|
38 |
|
39 |
-
|
40 |
-
|
41 |
-
|
|
|
|
|
|
|
|
|
42 |
|
43 |
if __name__ == "__main__":
|
44 |
-
|
45 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from flask import Flask, request, jsonify, render_template
|
2 |
+
from flask_socketio import SocketIO, emit
|
3 |
+
import json
|
4 |
+
import uuid
|
5 |
+
import os
|
6 |
+
from datetime import datetime
|
7 |
|
8 |
app = Flask(__name__)
|
9 |
+
app.config['SECRET_KEY'] = 'your-secret-key'
|
10 |
+
socketio = SocketIO(app)
|
11 |
|
12 |
+
# Job storage with unique IDs and status
|
13 |
+
jobs = []
|
14 |
+
connected_clients = {}
|
15 |
+
|
16 |
+
def save_jobs():
|
17 |
+
"""Save jobs to JSON file"""
|
18 |
+
try:
|
19 |
+
with open('jobs.json', 'w') as f:
|
20 |
+
json.dump(jobs, f)
|
21 |
+
except Exception as e:
|
22 |
+
print(f"Error saving jobs: {e}")
|
23 |
+
|
24 |
+
def load_jobs():
|
25 |
+
"""Load jobs from JSON file"""
|
26 |
+
try:
|
27 |
+
if os.path.exists('jobs.json') and os.path.getsize('jobs.json') > 0:
|
28 |
+
with open('jobs.json', 'r') as f:
|
29 |
+
return json.load(f)
|
30 |
+
except Exception as e:
|
31 |
+
print(f"Error loading jobs: {e}")
|
32 |
+
return []
|
33 |
|
34 |
@app.route('/')
|
35 |
+
def index():
|
36 |
+
return render_template('index.html')
|
|
|
37 |
|
38 |
+
@app.route('/submit_job', methods=['POST'])
|
39 |
+
def submit_job():
|
40 |
+
youtube_url = request.form.get("youtube_url")
|
41 |
+
exit_time = int(request.form.get("exit_time", 10))
|
42 |
+
mode = request.form.get("mode", "once")
|
43 |
+
job_id = str(uuid.uuid4())
|
44 |
|
45 |
+
job = {
|
46 |
+
"job_id": job_id,
|
47 |
+
"youtube_url": youtube_url,
|
48 |
+
"exit_time": exit_time,
|
49 |
+
"mode": mode,
|
50 |
+
"status": "pending"
|
51 |
+
}
|
52 |
+
jobs.append(job)
|
53 |
+
save_jobs()
|
54 |
|
55 |
+
return jsonify({"message": "Job submitted successfully", "job_id": job_id})
|
56 |
+
|
57 |
+
@socketio.on('client_info')
|
58 |
+
def handle_client_info(data):
|
59 |
+
client_id = request.sid
|
60 |
+
connected_clients[client_id] = {
|
61 |
+
'ip': data.get('ip', 'Unknown'),
|
62 |
+
'country': data.get('country', 'Unknown'),
|
63 |
+
'city': data.get('city', 'Unknown'),
|
64 |
+
'connected_at': datetime.now().isoformat()
|
65 |
+
}
|
66 |
+
|
67 |
+
emit('client_connected', {
|
68 |
+
'client_id': client_id,
|
69 |
+
'ip': data.get('ip', 'Unknown'),
|
70 |
+
'country': data.get('country', 'Unknown'),
|
71 |
+
'city': data.get('city', 'Unknown')
|
72 |
+
}, broadcast=True)
|
73 |
+
|
74 |
+
@socketio.on('disconnect')
|
75 |
+
def handle_disconnect():
|
76 |
+
client_id = request.sid
|
77 |
+
if client_id in connected_clients:
|
78 |
+
del connected_clients[client_id]
|
79 |
+
emit('client_disconnected', client_id, broadcast=True)
|
80 |
+
|
81 |
+
@app.route('/get_job', methods=['GET'])
|
82 |
+
def get_job():
|
83 |
+
for job in jobs:
|
84 |
+
if job["status"] == "pending":
|
85 |
+
return jsonify(job)
|
86 |
+
return jsonify({"message": "No pending jobs"})
|
87 |
|
88 |
+
@app.route('/update_job_status', methods=['POST'])
|
89 |
+
def update_job_status():
|
90 |
+
data = request.get_json()
|
91 |
+
job_id = data.get("job_id")
|
92 |
+
status = data.get("status", "done")
|
93 |
|
94 |
+
for job in jobs:
|
95 |
+
if job["job_id"] == job_id:
|
96 |
+
job["status"] = status
|
97 |
+
break
|
98 |
+
|
99 |
+
save_jobs()
|
100 |
+
return jsonify({"message": f"Job {job_id} marked as {status}"})
|
101 |
|
102 |
if __name__ == "__main__":
|
103 |
+
jobs = load_jobs()
|
104 |
+
|
105 |
+
if not os.path.exists('templates'):
|
106 |
+
os.makedirs('templates')
|
107 |
+
|
108 |
+
template_path = os.path.join('templates', 'index.html')
|
109 |
+
if not os.path.exists(template_path):
|
110 |
+
with open(template_path, 'w') as f:
|
111 |
+
f.write('''<!DOCTYPE html>
|
112 |
+
<html lang="en">
|
113 |
+
<head>
|
114 |
+
<meta charset="UTF-8">
|
115 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
116 |
+
<title>YouTube Job Manager</title>
|
117 |
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
118 |
+
<style>
|
119 |
+
body { padding: 20px; }
|
120 |
+
.connection-status { margin-bottom: 20px; }
|
121 |
+
</style>
|
122 |
+
</head>
|
123 |
+
<body>
|
124 |
+
<div class="container">
|
125 |
+
<div class="row">
|
126 |
+
<div class="col-md-8 offset-md-2">
|
127 |
+
<h1 class="mb-4">YouTube Job Manager</h1>
|
128 |
+
|
129 |
+
<div class="card mb-4">
|
130 |
+
<div class="card-header">
|
131 |
+
<h5 class="mb-0">Connected Clients</h5>
|
132 |
+
</div>
|
133 |
+
<div class="card-body">
|
134 |
+
<table class="table" id="clientsTable">
|
135 |
+
<thead>
|
136 |
+
<tr>
|
137 |
+
<th>IP Address</th>
|
138 |
+
<th>Country</th>
|
139 |
+
<th>City</th>
|
140 |
+
<th>Status</th>
|
141 |
+
</tr>
|
142 |
+
</thead>
|
143 |
+
<tbody id="clientsTableBody">
|
144 |
+
</tbody>
|
145 |
+
</table>
|
146 |
+
</div>
|
147 |
+
</div>
|
148 |
+
|
149 |
+
<div class="card">
|
150 |
+
<div class="card-header">
|
151 |
+
<h5 class="mb-0">Submit New Job</h5>
|
152 |
+
</div>
|
153 |
+
<div class="card-body">
|
154 |
+
<form action="/submit_job" method="post" class="needs-validation" novalidate>
|
155 |
+
<div class="mb-3">
|
156 |
+
<label for="youtube_url" class="form-label">YouTube URL:</label>
|
157 |
+
<input type="text" class="form-control" id="youtube_url" name="youtube_url" required>
|
158 |
+
</div>
|
159 |
+
|
160 |
+
<div class="mb-3">
|
161 |
+
<label for="exit_time" class="form-label">Exit Time (seconds):</label>
|
162 |
+
<input type="number" class="form-control" id="exit_time" name="exit_time" value="10" required>
|
163 |
+
</div>
|
164 |
+
|
165 |
+
<div class="mb-3">
|
166 |
+
<label for="mode" class="form-label">Mode:</label>
|
167 |
+
<select class="form-select" id="mode" name="mode">
|
168 |
+
<option value="once">Once</option>
|
169 |
+
<option value="again">Again</option>
|
170 |
+
<option value="continuous">Continuous</option>
|
171 |
+
</select>
|
172 |
+
</div>
|
173 |
+
|
174 |
+
<button type="submit" class="btn btn-primary">Submit Job</button>
|
175 |
+
</form>
|
176 |
+
</div>
|
177 |
+
</div>
|
178 |
+
</div>
|
179 |
+
</div>
|
180 |
+
</div>
|
181 |
+
|
182 |
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
183 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
|
184 |
+
<script>
|
185 |
+
const socket = io();
|
186 |
+
|
187 |
+
socket.on('connect', () => {
|
188 |
+
console.log('Connected to server');
|
189 |
+
});
|
190 |
+
|
191 |
+
socket.on('client_connected', (data) => {
|
192 |
+
const tableBody = document.getElementById('clientsTableBody');
|
193 |
+
const row = document.createElement('tr');
|
194 |
+
row.setAttribute('data-client-id', data.client_id);
|
195 |
+
row.innerHTML = `
|
196 |
+
<td>${data.ip}</td>
|
197 |
+
<td>${data.country}</td>
|
198 |
+
<td>${data.city}</td>
|
199 |
+
<td><span class="badge bg-success">Connected</span></td>
|
200 |
+
`;
|
201 |
+
tableBody.appendChild(row);
|
202 |
+
});
|
203 |
+
|
204 |
+
socket.on('client_disconnected', (clientId) => {
|
205 |
+
const row = document.querySelector(`tr[data-client-id="${clientId}"]`);
|
206 |
+
if (row) {
|
207 |
+
row.querySelector('.badge').className = 'badge bg-danger';
|
208 |
+
row.querySelector('.badge').textContent = 'Disconnected';
|
209 |
+
}
|
210 |
+
});
|
211 |
+
</script>
|
212 |
+
</body>
|
213 |
+
</html>
|
214 |
+
''')
|
215 |
+
|
216 |
+
socketio.run(app, host="0.0.0.0", port=7860 debug=False)
|