# 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''' {icon} {title if title else 'Book'} ISBN: {isbn} ''' 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 }