joermd commited on
Commit
827756a
·
verified ·
1 Parent(s): def27e4

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +419 -0
app.py ADDED
@@ -0,0 +1,419 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify, send_file
2
+ import whois
3
+ import requests
4
+ from urllib.parse import urlparse
5
+ import os
6
+
7
+ app = Flask(__name__)
8
+
9
+ # Store the HTML content in a variable
10
+ HTML_CONTENT = '''<!DOCTYPE html>
11
+ <html dir="rtl" lang="ar">
12
+ <head>
13
+ <meta charset="UTF-8">
14
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
15
+ <title>سبيدي | فاحص المواقع السريع</title>
16
+ <style>
17
+ @import url('https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700&display=swap');
18
+
19
+ :root {
20
+ --speedy-primary: #8B4513;
21
+ --speedy-dark: #5C2C0B;
22
+ --speedy-light: #F5E6DB;
23
+ --speedy-accent: #D2691E;
24
+ --speedy-bg: #FDF9F6;
25
+ --speedy-text: #3E2723;
26
+ --speedy-border: #DEB887;
27
+ --speedy-gradient: linear-gradient(135deg, #8B4513 0%, #5C2C0B 100%);
28
+ --speedy-shadow: 0 4px 6px rgba(139, 69, 19, 0.2);
29
+ }
30
+
31
+ body {
32
+ font-family: 'Cairo', sans-serif;
33
+ margin: 0;
34
+ padding: 20px;
35
+ background: var(--speedy-bg);
36
+ color: var(--speedy-text);
37
+ line-height: 1.6;
38
+ }
39
+
40
+ .container {
41
+ max-width: 900px;
42
+ margin: 20px auto;
43
+ background: white;
44
+ padding: 30px;
45
+ border-radius: 20px;
46
+ box-shadow: var(--speedy-shadow);
47
+ border: 1px solid var(--speedy-border);
48
+ }
49
+
50
+ .brand {
51
+ text-align: center;
52
+ margin-bottom: 10px;
53
+ }
54
+
55
+ .logo {
56
+ font-size: 3em;
57
+ font-weight: 700;
58
+ color: var(--speedy-primary);
59
+ text-shadow: 2px 2px 4px rgba(139, 69, 19, 0.2);
60
+ margin: 0;
61
+ }
62
+
63
+ .tagline {
64
+ color: var(--speedy-accent);
65
+ font-size: 1.2em;
66
+ margin-top: 5px;
67
+ }
68
+
69
+ h1 {
70
+ text-align: center;
71
+ color: var(--speedy-dark);
72
+ font-size: 2em;
73
+ margin: 20px 0;
74
+ font-weight: 700;
75
+ }
76
+
77
+ .input-group {
78
+ display: flex;
79
+ gap: 15px;
80
+ margin: 30px auto;
81
+ max-width: 700px;
82
+ padding: 20px;
83
+ background: var(--speedy-light);
84
+ border-radius: 16px;
85
+ box-shadow: inset 0 2px 4px rgba(92, 44, 11, 0.1);
86
+ }
87
+
88
+ input {
89
+ flex: 1;
90
+ padding: 15px 20px;
91
+ border: 2px solid var(--speedy-border);
92
+ border-radius: 12px;
93
+ font-size: 16px;
94
+ transition: all 0.3s ease;
95
+ font-family: 'Cairo', sans-serif;
96
+ background: white;
97
+ color: var(--speedy-text);
98
+ }
99
+
100
+ input:focus {
101
+ outline: none;
102
+ border-color: var(--speedy-primary);
103
+ box-shadow: 0 0 0 3px rgba(139, 69, 19, 0.2);
104
+ }
105
+
106
+ input::placeholder {
107
+ color: var(--speedy-border);
108
+ }
109
+
110
+ button {
111
+ padding: 15px 30px;
112
+ background: var(--speedy-gradient);
113
+ color: white;
114
+ border: none;
115
+ border-radius: 12px;
116
+ cursor: pointer;
117
+ font-size: 16px;
118
+ font-weight: 600;
119
+ transition: all 0.3s ease;
120
+ font-family: 'Cairo', sans-serif;
121
+ }
122
+
123
+ button:hover {
124
+ transform: translateY(-2px);
125
+ box-shadow: 0 6px 12px rgba(92, 44, 11, 0.3);
126
+ }
127
+
128
+ button:active {
129
+ transform: translateY(0);
130
+ background: var(--speedy-dark);
131
+ }
132
+
133
+ button:disabled {
134
+ background: var(--speedy-border);
135
+ transform: none;
136
+ box-shadow: none;
137
+ }
138
+
139
+ .loading {
140
+ text-align: center;
141
+ display: none;
142
+ margin: 20px 0;
143
+ color: var(--speedy-primary);
144
+ font-weight: 600;
145
+ }
146
+
147
+ .loading::after {
148
+ content: '🚀';
149
+ display: inline-block;
150
+ margin-right: 10px;
151
+ animation: rocket 1s infinite;
152
+ }
153
+
154
+ @keyframes rocket {
155
+ 0% { transform: translateY(0) rotate(45deg); }
156
+ 50% { transform: translateY(-10px) rotate(45deg); }
157
+ 100% { transform: translateY(0) rotate(45deg); }
158
+ }
159
+
160
+ .results {
161
+ margin-top: 30px;
162
+ display: none;
163
+ animation: fadeIn 0.5s ease;
164
+ }
165
+
166
+ @keyframes fadeIn {
167
+ from { opacity: 0; transform: translateY(20px); }
168
+ to { opacity: 1; transform: translateY(0); }
169
+ }
170
+
171
+ .results-section {
172
+ background: white;
173
+ border-radius: 16px;
174
+ padding: 25px;
175
+ margin-bottom: 20px;
176
+ border: 1px solid var(--speedy-border);
177
+ transition: all 0.3s ease;
178
+ }
179
+
180
+ .results-section:hover {
181
+ transform: translateY(-3px);
182
+ box-shadow: var(--speedy-shadow);
183
+ border-color: var(--speedy-primary);
184
+ }
185
+
186
+ .results h2 {
187
+ color: var(--speedy-dark);
188
+ border-bottom: 2px solid var(--speedy-primary);
189
+ padding-bottom: 10px;
190
+ margin-bottom: 20px;
191
+ }
192
+
193
+ .info-item {
194
+ display: flex;
195
+ justify-content: space-between;
196
+ padding: 12px;
197
+ border-bottom: 1px solid var(--speedy-light);
198
+ transition: background-color 0.2s ease;
199
+ }
200
+
201
+ .info-item:hover {
202
+ background-color: var(--speedy-bg);
203
+ border-radius: 8px;
204
+ }
205
+
206
+ .info-item:last-child {
207
+ border-bottom: none;
208
+ }
209
+
210
+ .info-label {
211
+ font-weight: 600;
212
+ color: var(--speedy-text);
213
+ }
214
+
215
+ .info-value {
216
+ color: var(--speedy-primary);
217
+ }
218
+
219
+ .error {
220
+ color: #D35400;
221
+ background: rgba(211, 84, 0, 0.1);
222
+ padding: 15px;
223
+ border-radius: 12px;
224
+ text-align: center;
225
+ margin: 20px 0;
226
+ display: none;
227
+ border: 1px solid rgba(211, 84, 0, 0.3);
228
+ }
229
+
230
+ @media (max-width: 768px) {
231
+ .input-group {
232
+ flex-direction: column;
233
+ }
234
+
235
+ button {
236
+ width: 100%;
237
+ }
238
+
239
+ .container {
240
+ padding: 20px;
241
+ }
242
+
243
+ .logo {
244
+ font-size: 2.5em;
245
+ }
246
+ }
247
+ </style>
248
+ </head>
249
+ <body>
250
+ <div class="container">
251
+ <div class="brand">
252
+ <h1 class="logo">سبيدي</h1>
253
+ <div class="tagline">فاحص المواقع السريع والذكي</div>
254
+ </div>
255
+
256
+ <div class="input-group">
257
+ <input type="url" id="urlInput" placeholder="https://example.com" dir="ltr">
258
+ <button onclick="checkUrl()">فحص سريع</button>
259
+ </div>
260
+
261
+ <div class="loading" id="loading">
262
+ جاري التحليل السريع للموقع...
263
+ </div>
264
+
265
+ <div class="error" id="error"></div>
266
+
267
+ <div class="results" id="results">
268
+ <div class="results-section">
269
+ <h2>معلومات الموقع</h2>
270
+ <div id="info"></div>
271
+ </div>
272
+
273
+ <div class="results-section">
274
+ <h2>نصائح تحسين الموقع</h2>
275
+ <div id="tips"></div>
276
+ </div>
277
+
278
+ <div class="results-section">
279
+ <h2>تحليل الزيارات</h2>
280
+ <div id="traffic"></div>
281
+ </div>
282
+ </div>
283
+ </div>
284
+
285
+ <script>
286
+ async function checkUrl() {
287
+ const urlInput = document.getElementById('urlInput');
288
+ const loading = document.getElementById('loading');
289
+ const results = document.getElementById('results');
290
+ const error = document.getElementById('error');
291
+ const button = document.querySelector('button');
292
+
293
+ if (!urlInput.value) {
294
+ error.textContent = 'الرجاء إدخال رابط صالح للفحص';
295
+ error.style.display = 'block';
296
+ return;
297
+ }
298
+
299
+ error.style.display = 'none';
300
+ results.style.display = 'none';
301
+ loading.style.display = 'block';
302
+ button.disabled = true;
303
+
304
+ try {
305
+ const response = await fetch('/check-url', {
306
+ method: 'POST',
307
+ headers: {
308
+ 'Content-Type': 'application/json',
309
+ },
310
+ body: JSON.stringify({ url: urlInput.value })
311
+ });
312
+
313
+ const data = await response.json();
314
+
315
+ if (data.error) {
316
+ error.textContent = data.error;
317
+ error.style.display = 'block';
318
+ } else {
319
+ document.getElementById('info').innerHTML = formatInfo(data.info);
320
+ document.getElementById('tips').innerHTML = formatList(data.tips);
321
+ document.getElementById('traffic').innerHTML = formatList(data.traffic_estimate);
322
+ results.style.display = 'block';
323
+ }
324
+ } catch (err) {
325
+ error.textContent = 'عذراً، حدث خطأ أثناء الاتصال بالخادم';
326
+ error.style.display = 'block';
327
+ } finally {
328
+ loading.style.display = 'none';
329
+ button.disabled = false;
330
+ }
331
+ }
332
+
333
+ function formatInfo(info) {
334
+ return Object.entries(info)
335
+ .map(([key, value]) => `
336
+ <div class="info-item">
337
+ <span class="info-label">${key}</span>
338
+ <span class="info-value">${value}</span>
339
+ </div>
340
+ `).join('');
341
+ }
342
+
343
+ function formatList(items) {
344
+ return items
345
+ .map(item => `<div class="info-item">${item}</div>`)
346
+ .join('');
347
+ }
348
+ </script>
349
+ </body>
350
+ </html>'''
351
+
352
+ def get_url_info(url):
353
+ try:
354
+ response = requests.get(url, timeout=10)
355
+ response.raise_for_status()
356
+
357
+ domain = urlparse(url).netloc
358
+ domain_info = whois.whois(domain)
359
+ registrar = domain_info.get('registrar', 'غير متوفر')
360
+ creation_date = domain_info.get('creation_date', 'غير متوفر')
361
+ expiration_date = domain_info.get('expiration_date', 'غير متوفر')
362
+
363
+ info = {
364
+ 'رابط': url,
365
+ 'بروتوكول': urlparse(url).scheme,
366
+ 'النطاق': domain,
367
+ 'رمز الحالة': response.status_code,
368
+ 'حجم المحتوى (بايت)': len(response.content),
369
+ 'نوع المحتوى': response.headers.get('Content-Type', 'غير متوفر'),
370
+ 'تاريخ الاستجابة': response.headers.get('Date', 'غير متوفر'),
371
+ 'مسجل النطاق': registrar,
372
+ 'تاريخ تسجيل النطاق': str(creation_date),
373
+ 'تاريخ انتهاء النطاق': str(expiration_date)
374
+ }
375
+
376
+ return info
377
+ except requests.RequestException as e:
378
+ return {'error': f'خطأ في الوصول إلى الرابط {url}: {e}'}
379
+ except Exception as e:
380
+ return {'error': f'حدث خطأ أثناء جمع المعلومات: {e}'}
381
+
382
+ def provide_website_tips(status_code):
383
+ tips = []
384
+ if status_code == 200:
385
+ tips.append("- الموقع يعمل بشكل جيد. تأكد من تحسين سرعة التحميل وتجربة المستخدم.")
386
+ elif status_code == 404:
387
+ tips.append("- الصفحة غير موجودة. تأكد من تحديث الروابط أو إنشاء صفحة 404 مخصصة.")
388
+ elif status_code >= 500:
389
+ tips.append("- خطأ في الخادم. تحقق من تكوين الخادم وتأكد من عدم وجود مشاكل في البرمجة.")
390
+ else:
391
+ tips.append(f"- حالة غير متوقعة: {status_code}. تحقق من إعدادات الخادم وتحسين جودة الموقع.")
392
+ return tips
393
+
394
+ def estimate_traffic(url):
395
+ traffic_estimate = []
396
+ if 'example.com' in url:
397
+ traffic_estimate.append("- الموقع يستخدم مثالاً، لذا تقدير الزيارات غير ممكن.")
398
+ else:
399
+ if 'edu' in urlparse(url).netloc:
400
+ traffic_estimate.append("- المواقع التعليمية غالباً ما يكون لديها حركة مرور معتدلة إلى مرتفعة.")
401
+ else:
402
+ traffic_estimate.append("- تقدير عدد الزيارات غير متاح بدون أدوات تحليل متقدمة.")
403
+ return traffic_estimate
404
+
405
+ @app.route('/')
406
+ def index():
407
+ return HTML_CONTENT
408
+
409
+ @app.route('/check-url', methods=['POST'])
410
+ def check_url():
411
+ data = request.json
412
+ url = data.get('url', '')
413
+
414
+ if not url:
415
+ return jsonify({'error': 'مطلوب إدخال الرابط'}), 400
416
+
417
+ info = get_url_info(url)
418
+ if 'error' in info:
419
+ return jsonify({'error': info['error']}