Spaces:
Runtime error
Runtime error
Update bot.py
Browse files
bot.py
CHANGED
|
@@ -607,9 +607,19 @@ class ImageToolbox:
|
|
| 607 |
return False
|
| 608 |
|
| 609 |
# ================================
|
| 610 |
-
# 📥
|
| 611 |
# ================================
|
| 612 |
class DownloadManager:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 613 |
@staticmethod
|
| 614 |
def extract_archives(folder):
|
| 615 |
for root, _, files in os.walk(folder):
|
|
@@ -630,8 +640,7 @@ class DownloadManager:
|
|
| 630 |
except: pass
|
| 631 |
|
| 632 |
@staticmethod
|
| 633 |
-
def
|
| 634 |
-
# 🚀 تحديث جذري لسحب مواقع الويب وحل مشكلة صورتين فقط (Lazy Loading Fix)
|
| 635 |
driver = None
|
| 636 |
try:
|
| 637 |
chrome_options = Options()
|
|
@@ -645,70 +654,163 @@ class DownloadManager:
|
|
| 645 |
driver.get(url)
|
| 646 |
time.sleep(5)
|
| 647 |
|
| 648 |
-
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
|
| 652 |
-
|
| 653 |
-
|
| 654 |
-
|
| 655 |
-
|
| 656 |
-
|
| 657 |
-
|
| 658 |
-
last_h = new_h
|
| 659 |
|
| 660 |
-
time.sleep(
|
| 661 |
|
| 662 |
-
|
| 663 |
-
|
| 664 |
-
|
| 665 |
-
|
| 666 |
-
|
| 667 |
-
|
| 668 |
-
urls.append(src)
|
| 669 |
|
| 670 |
-
|
| 671 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 672 |
|
| 673 |
-
|
| 674 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 675 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 676 |
for idx, u in enumerate(urls):
|
| 677 |
try:
|
| 678 |
-
c = requests.get(u, headers=req_headers, timeout=
|
| 679 |
im = Image.open(io.BytesIO(c)).convert('RGB')
|
| 680 |
-
|
| 681 |
-
|
| 682 |
-
path = os.path.join(output_folder, f"page_{idx:03d}.jpg")
|
| 683 |
im.save(path)
|
| 684 |
saved_paths.append(path)
|
| 685 |
except: pass
|
| 686 |
-
|
| 687 |
title = driver.title.split('|')[0].strip() if driver.title else "Web_Chapter"
|
| 688 |
title = re.sub(r'[\\/*?:"<>|]', "", title)
|
| 689 |
driver.quit()
|
| 690 |
return saved_paths, title
|
| 691 |
except Exception as e:
|
| 692 |
if driver: driver.quit()
|
| 693 |
-
print(f"Scraper Error: {e}")
|
| 694 |
return [], "Error"
|
| 695 |
|
| 696 |
@staticmethod
|
| 697 |
async def download(url, output_folder):
|
| 698 |
success = False
|
| 699 |
name = "Downloaded_Content"
|
| 700 |
-
|
| 701 |
-
# التوجه مباشرة لخطة الطوارئ gdown لتحميل الملفات
|
| 702 |
if "drive.google.com" in url:
|
| 703 |
-
|
| 704 |
-
|
| 705 |
-
|
| 706 |
-
if res: success = True
|
| 707 |
-
else:
|
| 708 |
-
res = await asyncio.to_thread(gdown.download, url, output=os.path.join(output_folder, "gdown_fallback.zip"), quiet=False, fuzzy=True)
|
| 709 |
-
if res: success = True
|
| 710 |
-
if success: name = "Drive_Content"
|
| 711 |
-
except Exception as e: print(f"Drive Error: {e}")
|
| 712 |
else:
|
| 713 |
try:
|
| 714 |
async with aiohttp.ClientSession() as s:
|
|
@@ -716,11 +818,10 @@ class DownloadManager:
|
|
| 716 |
if r.status == 200:
|
| 717 |
cd = r.headers.get('Content-Disposition', '')
|
| 718 |
if 'filename=' in cd: name = re.findall("filename=(.+)", cd)[0].strip('"')
|
| 719 |
-
else: name = "file.
|
| 720 |
with open(os.path.join(output_folder, name), 'wb') as f: f.write(await r.read())
|
| 721 |
success = True
|
| 722 |
except: pass
|
| 723 |
-
|
| 724 |
DownloadManager.extract_archives(output_folder)
|
| 725 |
has_images = any(f.lower().endswith(('.png','.jpg','.jpeg','.webp')) for r, d, files in os.walk(output_folder) for f in files)
|
| 726 |
if success and has_images: return True, name
|
|
@@ -732,13 +833,12 @@ class DownloadManager:
|
|
| 732 |
subdirs = [d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d))]
|
| 733 |
if not subdirs:
|
| 734 |
imgs = [os.path.join(folder, f) for f in os.listdir(folder) if f.lower().endswith(('.png','.jpg','.jpeg','.webp'))]
|
| 735 |
-
|
| 736 |
-
if imgs: chapters["Main"] = sorted(imgs, key=natural_sort_key)
|
| 737 |
else:
|
| 738 |
-
for d in sorted(subdirs
|
| 739 |
d_path = os.path.join(folder, d)
|
| 740 |
imgs = [os.path.join(d_path, f) for f in os.listdir(d_path) if f.lower().endswith(('.png','.jpg','.jpeg','.webp'))]
|
| 741 |
-
if imgs: chapters[d] = sorted(imgs
|
| 742 |
return chapters
|
| 743 |
|
| 744 |
# ================================
|
|
|
|
| 607 |
return False
|
| 608 |
|
| 609 |
# ================================
|
| 610 |
+
# 📥 Universal Downloader (Drive, Gofile, Web & gdown Fallback)
|
| 611 |
# ================================
|
| 612 |
class DownloadManager:
|
| 613 |
+
@staticmethod
|
| 614 |
+
def get_drive_real_name(url):
|
| 615 |
+
try:
|
| 616 |
+
r = requests.get(url, timeout=10)
|
| 617 |
+
soup = BeautifulSoup(r.text, 'html.parser')
|
| 618 |
+
title = soup.title.string
|
| 619 |
+
if title: return title.replace(" - Google Drive", "").strip()
|
| 620 |
+
return "Drive_Content"
|
| 621 |
+
except: return "Drive_Content"
|
| 622 |
+
|
| 623 |
@staticmethod
|
| 624 |
def extract_archives(folder):
|
| 625 |
for root, _, files in os.walk(folder):
|
|
|
|
| 640 |
except: pass
|
| 641 |
|
| 642 |
@staticmethod
|
| 643 |
+
def scrape_drive_selenium(url, output_folder):
|
|
|
|
| 644 |
driver = None
|
| 645 |
try:
|
| 646 |
chrome_options = Options()
|
|
|
|
| 654 |
driver.get(url)
|
| 655 |
time.sleep(5)
|
| 656 |
|
| 657 |
+
page_title = driver.title.replace(" - Google Drive", "").strip()
|
| 658 |
+
if not page_title or page_title == "Google Drive": page_title = "Drive_Folder"
|
| 659 |
+
|
| 660 |
+
last_height = driver.execute_script("return document.body.scrollHeight")
|
| 661 |
+
for _ in range(15):
|
| 662 |
+
driver.execute_script("window.scrollBy(0, 1500);")
|
| 663 |
+
time.sleep(1)
|
| 664 |
+
new_height = driver.execute_script("return document.body.scrollHeight")
|
| 665 |
+
if new_height == last_height: break
|
| 666 |
+
last_height = new_height
|
|
|
|
| 667 |
|
| 668 |
+
time.sleep(2)
|
| 669 |
|
| 670 |
+
elements = driver.find_elements(By.XPATH, "//*[@data-id]")
|
| 671 |
+
file_ids = []
|
| 672 |
+
for el in elements:
|
| 673 |
+
fid = el.get_attribute("data-id")
|
| 674 |
+
if fid and len(fid) > 20 and fid not in file_ids:
|
| 675 |
+
file_ids.append(fid)
|
|
|
|
| 676 |
|
| 677 |
+
if not file_ids:
|
| 678 |
+
page_source = driver.page_source
|
| 679 |
+
found = re.findall(r'\["([^"]{25,})",', page_source)
|
| 680 |
+
file_ids = list(set([fid for fid in found if len(fid) > 28]))
|
| 681 |
+
|
| 682 |
+
if not file_ids:
|
| 683 |
+
driver.quit()
|
| 684 |
+
return False, "Error"
|
| 685 |
+
|
| 686 |
+
saved = False
|
| 687 |
+
session = requests.Session()
|
| 688 |
+
session.headers.update({"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"})
|
| 689 |
|
| 690 |
+
for idx, fid in enumerate(file_ids):
|
| 691 |
+
try:
|
| 692 |
+
dl_url = f"https://drive.google.com/uc?export=download&id={fid}"
|
| 693 |
+
r = session.get(dl_url, stream=True, timeout=15)
|
| 694 |
+
if r.status_code == 200 and len(r.content) > 10000:
|
| 695 |
+
with open(os.path.join(output_folder, f"drive_img_{idx:03d}.jpg"), 'wb') as f:
|
| 696 |
+
f.write(r.content)
|
| 697 |
+
saved = True
|
| 698 |
+
except: pass
|
| 699 |
|
| 700 |
+
driver.quit()
|
| 701 |
+
return saved, page_title
|
| 702 |
+
except Exception as e:
|
| 703 |
+
if driver: driver.quit()
|
| 704 |
+
return False, "Error"
|
| 705 |
+
|
| 706 |
+
@staticmethod
|
| 707 |
+
async def scrape_drive(url, output_folder):
|
| 708 |
+
real_name = DownloadManager.get_drive_real_name(url)
|
| 709 |
+
# 1. المحاولة الأساسية باستخدام المتصفح الخفي (Selenium)
|
| 710 |
+
success, name = await asyncio.to_thread(DownloadManager.scrape_drive_selenium, url, output_folder)
|
| 711 |
+
|
| 712 |
+
# 2. خط الدفاع الأخير (Fallback) باستخدام gdown لو فشل المتصفح
|
| 713 |
+
if not success:
|
| 714 |
+
try:
|
| 715 |
+
print("⚠️ فشل السحب باستخدام Selenium، جاري التحويل إلى خطة الطوارئ (gdown)...")
|
| 716 |
+
if "folder" in url or "drive.google.com/drive/folders" in url:
|
| 717 |
+
res = await asyncio.to_thread(gdown.download_folder, url, output=output_folder, quiet=False, use_cookies=False)
|
| 718 |
+
if res: success = True
|
| 719 |
+
else:
|
| 720 |
+
res = await asyncio.to_thread(gdown.download, url, output=os.path.join(output_folder, "gdown_fallback.zip"), quiet=False, fuzzy=True)
|
| 721 |
+
if res: success = True
|
| 722 |
+
|
| 723 |
+
if success: name = real_name
|
| 724 |
+
except Exception as e:
|
| 725 |
+
print(f"❌ فشلت خطة الطوارئ gdown أيضاً: {e}")
|
| 726 |
+
|
| 727 |
+
return success, name
|
| 728 |
+
|
| 729 |
+
@staticmethod
|
| 730 |
+
def scrape_gofile_selenium(url, output_folder):
|
| 731 |
+
driver = None
|
| 732 |
+
try:
|
| 733 |
+
chrome_options = Options()
|
| 734 |
+
chrome_options.add_argument('--headless=new')
|
| 735 |
+
chrome_options.add_argument('--no-sandbox')
|
| 736 |
+
chrome_options.add_argument('--disable-dev-shm-usage')
|
| 737 |
+
service = Service(ChromeDriverManager().install())
|
| 738 |
+
driver = webdriver.Chrome(service=service, options=chrome_options)
|
| 739 |
+
driver.get(url)
|
| 740 |
+
WebDriverWait(driver, 15).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".contentName, .downloadButton")))
|
| 741 |
+
time.sleep(3)
|
| 742 |
+
try: page_title = driver.find_element(By.CSS_SELECTOR, ".contentName").text
|
| 743 |
+
except: page_title = "Gofile_Content"
|
| 744 |
+
links = driver.find_elements(By.TAG_NAME, 'a')
|
| 745 |
+
download_urls = [link.get_attribute('href') for link in links if link.get_attribute('href') and 'download' in link.get_attribute('href').lower()]
|
| 746 |
+
cookies = driver.get_cookies()
|
| 747 |
+
session = requests.Session()
|
| 748 |
+
for cookie in cookies: session.cookies.set(cookie['name'], cookie['value'])
|
| 749 |
+
saved = False
|
| 750 |
+
for idx, d_url in enumerate(list(set(download_urls))):
|
| 751 |
+
r = session.get(d_url, stream=True)
|
| 752 |
+
if r.status_code == 200:
|
| 753 |
+
cd = r.headers.get('content-disposition', '')
|
| 754 |
+
fname = re.findall("filename=(.+)", cd)
|
| 755 |
+
name = fname[0].strip('"') if fname else f"file_{idx}.zip"
|
| 756 |
+
with open(os.path.join(output_folder, name), 'wb') as f: f.write(r.content)
|
| 757 |
+
saved = True
|
| 758 |
+
driver.quit()
|
| 759 |
+
return saved, page_title
|
| 760 |
+
except:
|
| 761 |
+
if driver: driver.quit()
|
| 762 |
+
return False, "Error"
|
| 763 |
+
|
| 764 |
+
@staticmethod
|
| 765 |
+
def scrape_web_selenium(url, output_folder):
|
| 766 |
+
driver = None
|
| 767 |
+
try:
|
| 768 |
+
chrome_options = Options()
|
| 769 |
+
chrome_options.add_argument('--headless=new')
|
| 770 |
+
chrome_options.add_argument('--no-sandbox')
|
| 771 |
+
chrome_options.add_argument('--disable-dev-shm-usage')
|
| 772 |
+
service = Service(ChromeDriverManager().install())
|
| 773 |
+
driver = webdriver.Chrome(service=service, options=chrome_options)
|
| 774 |
+
driver.get(url)
|
| 775 |
+
time.sleep(5)
|
| 776 |
+
last_h = driver.execute_script("return document.body.scrollHeight")
|
| 777 |
+
for _ in range(30):
|
| 778 |
+
driver.execute_script("window.scrollBy(0, 800);")
|
| 779 |
+
time.sleep(0.5)
|
| 780 |
+
new_h = driver.execute_script("return window.pageYOffset + window.innerHeight")
|
| 781 |
+
if new_h >= last_h: break
|
| 782 |
+
last_h = driver.execute_script("return document.body.scrollHeight")
|
| 783 |
+
time.sleep(2)
|
| 784 |
+
elems = driver.find_elements(By.TAG_NAME, 'img')
|
| 785 |
+
urls = [e.get_attribute('src') or e.get_attribute('data-src') for e in elems]
|
| 786 |
+
urls = list(set([u for u in urls if u and u.startswith('http') and not any(x in u.lower() for x in ['logo','ad','banner','icon'])]))
|
| 787 |
+
saved_paths = []
|
| 788 |
+
req_headers = {'User-Agent': 'Mozilla/5.0'}
|
| 789 |
for idx, u in enumerate(urls):
|
| 790 |
try:
|
| 791 |
+
c = requests.get(u, headers=req_headers, timeout=10).content
|
| 792 |
im = Image.open(io.BytesIO(c)).convert('RGB')
|
| 793 |
+
if im.width > 150 and im.height > 150:
|
| 794 |
+
path = os.path.join(output_folder, f"{idx:03d}.jpg")
|
|
|
|
| 795 |
im.save(path)
|
| 796 |
saved_paths.append(path)
|
| 797 |
except: pass
|
|
|
|
| 798 |
title = driver.title.split('|')[0].strip() if driver.title else "Web_Chapter"
|
| 799 |
title = re.sub(r'[\\/*?:"<>|]', "", title)
|
| 800 |
driver.quit()
|
| 801 |
return saved_paths, title
|
| 802 |
except Exception as e:
|
| 803 |
if driver: driver.quit()
|
|
|
|
| 804 |
return [], "Error"
|
| 805 |
|
| 806 |
@staticmethod
|
| 807 |
async def download(url, output_folder):
|
| 808 |
success = False
|
| 809 |
name = "Downloaded_Content"
|
|
|
|
|
|
|
| 810 |
if "drive.google.com" in url:
|
| 811 |
+
success, name = await DownloadManager.scrape_drive(url, output_folder)
|
| 812 |
+
elif "gofile.io" in url:
|
| 813 |
+
success, name = await asyncio.to_thread(DownloadManager.scrape_gofile_selenium, url, output_folder)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 814 |
else:
|
| 815 |
try:
|
| 816 |
async with aiohttp.ClientSession() as s:
|
|
|
|
| 818 |
if r.status == 200:
|
| 819 |
cd = r.headers.get('Content-Disposition', '')
|
| 820 |
if 'filename=' in cd: name = re.findall("filename=(.+)", cd)[0].strip('"')
|
| 821 |
+
else: name = "file.bin"
|
| 822 |
with open(os.path.join(output_folder, name), 'wb') as f: f.write(await r.read())
|
| 823 |
success = True
|
| 824 |
except: pass
|
|
|
|
| 825 |
DownloadManager.extract_archives(output_folder)
|
| 826 |
has_images = any(f.lower().endswith(('.png','.jpg','.jpeg','.webp')) for r, d, files in os.walk(output_folder) for f in files)
|
| 827 |
if success and has_images: return True, name
|
|
|
|
| 833 |
subdirs = [d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d))]
|
| 834 |
if not subdirs:
|
| 835 |
imgs = [os.path.join(folder, f) for f in os.listdir(folder) if f.lower().endswith(('.png','.jpg','.jpeg','.webp'))]
|
| 836 |
+
if imgs: chapters["Main"] = sorted(imgs)
|
|
|
|
| 837 |
else:
|
| 838 |
+
for d in sorted(subdirs):
|
| 839 |
d_path = os.path.join(folder, d)
|
| 840 |
imgs = [os.path.join(d_path, f) for f in os.listdir(d_path) if f.lower().endswith(('.png','.jpg','.jpeg','.webp'))]
|
| 841 |
+
if imgs: chapters[d] = sorted(imgs)
|
| 842 |
return chapters
|
| 843 |
|
| 844 |
# ================================
|