SQU-Medical-Library / cover_fetcher.py
saifom's picture
Update cover_fetcher.py
60776e6 verified
Raw
History Blame
10.8 kB
# cover_fetcher.py
import requests
import os
import urllib.parse
from typing import Dict, Optional
class EnhancedCoverFetcher:
"""مسترد محسن لأغلفة الكتب من مصادر متعددة مع دعم HTTPS والفحص الذكي"""
def __init__(self):
self.sources = [
self._try_google_books,
self._try_openlibrary,
self._try_librarything,
self._try_amazon,
self._try_bookdepository,
self._try_barnes_noble,
self._try_via_placeholder, # ✅ مصدر احتياطي إضافي
self._try_fakeimg # ✅ مصدر احتياطي إضافي
]
def get_cover(self, isbn: str, title: Optional[str] = None) -> Dict:
"""الحصول على غلاف الكتاب من أفضل مصدر متاح"""
for source_func in self.sources:
try:
result = source_func(isbn)
if result and result.get('url') and self._is_image_accessible(result['url']):
return result
except Exception as e:
continue
return self._generate_smart_placeholder(isbn, title)
def _is_image_accessible(self, url: str) -> bool:
"""التحقق من أن الصورة قابلة للعرض (تستخدم GET بدلاً من HEAD)"""
try:
response = requests.get(url, timeout=5, stream=True)
content_type = response.headers.get('Content-Type', '')
return response.status_code == 200 and content_type.startswith('image/')
except:
return False
def _try_google_books(self, isbn: str) -> Optional[Dict]:
try:
url = f"https://www.googleapis.com/books/v1/volumes?q=isbn:{isbn}"
response = requests.get(url, timeout=5)
if response.status_code == 200:
data = response.json()
if 'items' in data and len(data['items']) > 0:
volume_info = data['items'][0]['volumeInfo']
image_links = volume_info.get('imageLinks', {})
cover_url = None
# الأولوية للصور الأكبر
for size in ['extraLarge', 'large', 'medium', 'small', 'thumbnail']:
if image_links.get(size):
cover_url = image_links[size]
break
if cover_url:
# تحويل HTTP إلى HTTPS
cover_url = cover_url.replace('http://', 'https://')
return {
'url': cover_url,
'source': 'Google Books',
'status': 'success',
'quality': 'high'
}
except:
pass
return None
def _try_openlibrary(self, isbn: str) -> Optional[Dict]:
try:
cover_url = f"https://covers.openlibrary.org/b/isbn/{isbn}-L.jpg"
if self._is_image_accessible(cover_url):
return {
'url': cover_url,
'source': 'OpenLibrary',
'status': 'success',
'quality': 'medium'
}
except:
pass
return None
def _try_librarything(self, isbn: str) -> Optional[Dict]:
api_key = os.getenv('LIBRARYTHING_KEY')
if not api_key:
return None
try:
cover_url = f"https://covers.librarything.com/devkey/{api_key}/large/isbn/{isbn}"
if self._is_image_accessible(cover_url):
return {
'url': cover_url,
'source': 'LibraryThing',
'status': 'success',
'quality': 'medium'
}
except:
pass
return None
def _try_amazon(self, isbn: str) -> Optional[Dict]:
try:
# Amazon يفضل ISBN-10
isbn_clean = isbn.replace('-', '')
cover_url = f"https://images-na.ssl-images-amazon.com/images/P/{isbn_clean}.01.LZZZZZZZ.jpg"
if self._is_image_accessible(cover_url):
return {
'url': cover_url,
'source': 'Amazon',
'status': 'success',
'quality': 'high'
}
except:
pass
return None
def _try_bookdepository(self, isbn: str) -> Optional[Dict]:
try:
cover_url = f"https://d1w7fb2mkkr3kw.cloudfront.net/assets/images/book/lrg/{isbn[:3]}/{isbn}.jpg"
if self._is_image_accessible(cover_url):
return {
'url': cover_url,
'source': 'Book Depository',
'status': 'success',
'quality': 'medium'
}
except:
pass
return None
def _try_barnes_noble(self, isbn: str) -> Optional[Dict]:
try:
# استخدام HTTPS
cover_url = f"https://images.barnesandnoble.com/pImages/{isbn}.jpg"
if self._is_image_accessible(cover_url):
return {
'url': cover_url,
'source': 'Barnes & Noble',
'status': 'success',
'quality': 'medium'
}
except:
pass
return None
def _try_via_placeholder(self, isbn: str) -> Optional[Dict]:
"""مصدر احتياطي - via.placeholder.com (خدمة صور افتراضية)"""
try:
cover_url = f"https://via.placeholder.com/400x600.png?text=ISBN%3A{isbn}"
return {
'url': cover_url,
'source': 'via.placeholder.com',
'status': 'fallback',
'quality': 'low'
}
except:
return None
def _try_fakeimg(self, isbn: str) -> Optional[Dict]:
"""مصدر احتياطي آخر - fakeimg.pl"""
try:
cover_url = f"https://fakeimg.pl/400x600/cccccc/666?text=ISBN%3A{isbn}"
return {
'url': cover_url,
'source': 'fakeimg.pl',
'status': 'fallback',
'quality': 'low'
}
except:
return None
def _generate_smart_placeholder(self, isbn: str, title: Optional[str] = None) -> Dict:
"""إنشاء placeholder ذكي باستخدام Data URI (يعمل حتى بدون إنترنت)"""
# ألوان مختلفة لأنواع الكتب
color_schemes = {
'medical': ('#e3f2fd', '#1565c0', '🏥'),
'science': ('#f3e5f5', '#7b1fa2', '🔬'),
'textbook': ('#fff3e0', '#ef6c00', '📚'),
'default': ('#f5f5f5', '#424242', '📖')
}
book_type = 'default'
if title:
title_lower = title.lower()
if any(word in title_lower for word in ['medical', 'medicine', 'clinic', 'hospital', 'surgery']):
book_type = 'medical'
elif any(word in title_lower for word in ['science', 'biology', 'chemistry', 'physics', 'anatomy']):
book_type = 'science'
elif any(word in title_lower for word in ['textbook', 'guide', 'manual', 'handbook', 'student']):
book_type = 'textbook'
bg_color, text_color, icon = color_schemes[book_type]
# إنشاء نص العرض
display_text = f"ISBN: {isbn}"
if title:
short_title = title[:25] + ('...' if len(title) > 25 else '')
display_text = f"{icon} {short_title}\nISBN: {isbn}"
# محاولة استخدام placehold.co أولاً
try:
encoded_text = urllib.parse.quote(display_text)
placeholder_url = f"https://placehold.co/400x600/{bg_color.strip('#')}/{text_color.strip('#')}?text={encoded_text}&font=roboto"
# تحقق من أن الخدمة تعمل
if self._is_image_accessible(placeholder_url):
return {
'url': placeholder_url,
'source': 'Smart Placeholder (placehold.co)',
'status': 'fallback',
'quality': 'low',
'type': book_type
}
except:
pass
# إذا فشل placehold.co، استخدم fakeimg.pl
try:
fakeimg_url = f"https://fakeimg.pl/400x600/{bg_color.strip('#')}/{text_color.strip('#')}?text={urllib.parse.quote(display_text)}"
return {
'url': fakeimg_url,
'source': 'Smart Placeholder (fakeimg.pl)',
'status': 'fallback',
'quality': 'low',
'type': book_type
}
except:
pass
# الحل الأخير: Data URI (صورة SVG داخلية، تعمل بدون إنترنت)
svg = f'''<svg width="400" height="600" xmlns="http://www.w3.org/2000/svg">
<rect width="400" height="600" fill="{bg_color}"/>
<text x="200" y="200" font-size="20" text-anchor="middle" fill="{text_color}" font-family="Arial, sans-serif">
{icon} {title if title else 'Book'}
</text>
<text x="200" y="300" font-size="16" text-anchor="middle" fill="{text_color}" font-family="Arial, sans-serif">
ISBN: {isbn}
</text>
</svg>'''
import base64
svg_base64 = base64.b64encode(svg.encode('utf-8')).decode('utf-8')
data_uri = f"data:image/svg+xml;base64,{svg_base64}"
return {
'url': data_uri,
'source': 'Data URI (local)',
'status': 'fallback',
'quality': 'low',
'type': book_type
}
def get_all_covers(self, isbn: str) -> Dict:
"""الحصول على جميع الأغلفة المتاحة"""
all_covers = []
for source_func in self.sources:
try:
result = source_func(isbn)
if result and result.get('url'):
all_covers.append(result)
except:
continue
if not all_covers:
placeholder = self._generate_smart_placeholder(isbn)
all_covers.append(placeholder)
return {
'total': len(all_covers),
'covers': all_covers,
'best': all_covers[0] if all_covers else None
}