codelion commited on
Commit
f4f1d01
·
verified ·
1 Parent(s): c2bf9a5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +35 -21
app.py CHANGED
@@ -2,9 +2,10 @@ from flask import Flask, request, render_template_string, Response, jsonify
2
  from openai import OpenAI
3
  import os
4
  import json
5
- from urllib.parse import quote
6
  import html
7
  import requests
 
8
 
9
  app = Flask(__name__)
10
 
@@ -67,19 +68,26 @@ def fetch_search_results(query):
67
 
68
  @app.route('/check-url', methods=['GET'])
69
  def check_url():
70
- """Check if a URL is valid (returns 200) or broken, following redirects."""
71
  url = request.args.get('url', '')
72
  if not url:
73
- return jsonify({'broken': True})
74
  try:
75
  # Follow redirects and check final status
76
- response = requests.head(url, allow_redirects=True, timeout=10)
77
  if response.status_code == 200:
78
- return jsonify({'broken': False})
 
 
 
 
 
 
 
79
  else:
80
- return jsonify({'broken': True})
81
  except requests.RequestException:
82
- return jsonify({'broken': True})
83
 
84
  @app.route('/', methods=['GET'])
85
  def search_page():
@@ -186,7 +194,7 @@ def search_page():
186
  .search-box input[type="text"] {{
187
  width: 100%; padding: 12px 20px; font-size: 16px;
188
  border: 1px solid #dfe1e5; border-radius: 24px;
189
- box-shadow: 0 1px 6px rgba(32,33,36,0.28);
190
  }}
191
  .search-box input[type="submit"] {{
192
  background-color: #f8f9fa; border: 1px solid #f8f9fa;
@@ -337,7 +345,7 @@ def search_page():
337
  .search-box input[type="text"] {{
338
  width: 100%; padding: 12px 20px; font-size: 16px;
339
  border: 1px solid #dfe1e5; border-radius: 24px;
340
- box-shadow: 0 1px 6px rgba(32,33,36,0.28); outline: none;
341
  }}
342
  .search-box input[type="submit"] {{
343
  background-color: #f8f9fa; border: 1px solid #f8f9fa;
@@ -350,9 +358,10 @@ def search_page():
350
  .search-buttons {{ text-align: center; }}
351
  .results {{ max-width: 652px; margin: 0 auto; }}
352
  .search-result {{ margin-bottom: 28px; }}
353
- .search-result a {{ color: #1a0dab; font-size: 20px; text-decoration: none; }}
354
  .search-result a:hover {{ text-decoration: underline; }}
355
  .search-result a.broken {{ color: #d93025; }}
 
356
  .search-result .url {{ color: #006621; font-size: 14px; line-height: 20px; }}
357
  .search-result p {{ color: #4d5156; font-size: 14px; line-height: 22px; margin: 0; }}
358
  .pagination {{ text-align: center; margin: 40px 0; }}
@@ -379,20 +388,25 @@ def search_page():
379
  }}
380
  async function checkLinks() {{
381
  const links = document.querySelectorAll('.search-result a');
382
- const promises = Array.from(links).map(link => {{
383
  const url = encodeURIComponent(link.href);
384
- return fetch('/check-url?url=' + url)
385
- .then(response => response.json())
386
- .then(data => {{
387
- if (data.broken) {{
388
- link.textContent += ' [Broken Link]';
389
- link.classList.add('broken');
390
- }}
391
- }})
392
- .catch(() => {{
393
  link.textContent += ' [Broken Link]';
394
  link.classList.add('broken');
395
- }});
 
 
 
 
 
 
 
 
 
 
396
  }});
397
  await Promise.all(promises);
398
  }}
 
2
  from openai import OpenAI
3
  import os
4
  import json
5
+ from urllib.parse import quote, urljoin
6
  import html
7
  import requests
8
+ from bs4 import BeautifulSoup
9
 
10
  app = Flask(__name__)
11
 
 
68
 
69
  @app.route('/check-url', methods=['GET'])
70
  def check_url():
71
+ """Check if a URL is valid (returns 200) or broken, and fetch favicon if valid."""
72
  url = request.args.get('url', '')
73
  if not url:
74
+ return jsonify({'broken': True, 'favicon': None})
75
  try:
76
  # Follow redirects and check final status
77
+ response = requests.head(url, allow_redirects=True, timeout=5)
78
  if response.status_code == 200:
79
+ # Fetch favicon for valid URLs
80
+ html_response = requests.get(url, timeout=5)
81
+ soup = BeautifulSoup(html_response.text, 'html.parser')
82
+ favicon_tag = soup.find("link", rel=["icon", "shortcut icon"])
83
+ favicon_url = favicon_tag['href'] if favicon_tag and 'href' in favicon_tag.attrs else None
84
+ if favicon_url and not favicon_url.startswith('http'):
85
+ favicon_url = urljoin(url, favicon_url) # Resolve relative URLs
86
+ return jsonify({'broken': False, 'favicon': favicon_url or '/static/default-favicon.ico'})
87
  else:
88
+ return jsonify({'broken': True, 'favicon': None})
89
  except requests.RequestException:
90
+ return jsonify({'broken': True, 'favicon': None})
91
 
92
  @app.route('/', methods=['GET'])
93
  def search_page():
 
194
  .search-box input[type="text"] {{
195
  width: 100%; padding: 12px 20px; font-size: 16px;
196
  border: 1px solid #dfe1e5; border-radius: 24px;
197
+ box-shadow: 0 1px 6px rgba(0,0,0,0.28);
198
  }}
199
  .search-box input[type="submit"] {{
200
  background-color: #f8f9fa; border: 1px solid #f8f9fa;
 
345
  .search-box input[type="text"] {{
346
  width: 100%; padding: 12px 20px; font-size: 16px;
347
  border: 1px solid #dfe1e5; border-radius: 24px;
348
+ box-shadow: 0 1px 6px rgba(0,0,0,0.28); outline: none;
349
  }}
350
  .search-box input[type="submit"] {{
351
  background-color: #f8f9fa; border: 1px solid #f8f9fa;
 
358
  .search-buttons {{ text-align: center; }}
359
  .results {{ max-width: 652px; margin: 0 auto; }}
360
  .search-result {{ margin-bottom: 28px; }}
361
+ .search-result a {{ color: #1a0dab; font-size: 20px; text-decoration: none; display: flex; align-items: center; }}
362
  .search-result a:hover {{ text-decoration: underline; }}
363
  .search-result a.broken {{ color: #d93025; }}
364
+ .search-result .favicon {{ width: 16px; height: 16px; margin-right: 8px; vertical-align: middle; }}
365
  .search-result .url {{ color: #006621; font-size: 14px; line-height: 20px; }}
366
  .search-result p {{ color: #4d5156; font-size: 14px; line-height: 22px; margin: 0; }}
367
  .pagination {{ text-align: center; margin: 40px 0; }}
 
388
  }}
389
  async function checkLinks() {{
390
  const links = document.querySelectorAll('.search-result a');
391
+ const promises = Array.from(links).map(async (link) => {{
392
  const url = encodeURIComponent(link.href);
393
+ try {{
394
+ const response = await fetch('/check-url?url=' + url);
395
+ const data = await response.json();
396
+ if (data.broken) {{
 
 
 
 
 
397
  link.textContent += ' [Broken Link]';
398
  link.classList.add('broken');
399
+ }} else if (data.favicon) {{
400
+ const img = document.createElement('img');
401
+ img.src = data.favicon;
402
+ img.className = 'favicon';
403
+ img.alt = 'Favicon';
404
+ link.insertBefore(img, link.firstChild);
405
+ }}
406
+ }} catch (error) {{
407
+ link.textContent += ' [Broken Link]';
408
+ link.classList.add('broken');
409
+ }}
410
  }});
411
  await Promise.all(promises);
412
  }}