import gradio as gr import datetime import json import re import pycountry # قد لا تكون ضرورية هنا ما لم نكن نعرض بيانات مستخدم من الفيديو from curl_cffi import requests from lxml import html # دالة لجلب تفاصيل الفيديو من رابط تيك توك def get_tiktok_video_details(video_url): # استخدام نمط regex لاستخلاص معرف الفيديو من الرابط (إذا كان موجوداً) # تيك توك لديها روابط مختلفة، مثل: # https://www.tiktok.com/@username/video/VIDEO_ID # https://www.tiktok.com/t/VIDEO_ID/ # https://vm.tiktok.com/ZM.../ match_video_id = re.search(r'(?:video/|/v/|/t/|vm\.tiktok\.com/ZM)([0-9A-Za-z_-]+)', video_url) if not match_video_id: return "خطأ: رابط الفيديو غير صالح. يرجى إدخال رابط فيديو تيك توك صحيح." video_id = match_video_id.group(1) # بناء رابط صفحة الفيديو (قد لا يكون URL الأساسي هو الأفضل دائماً، أحياناً vm.tiktok.com يعمل بشكل أفضل) # لكن سنستخدم الصيغة الأكثر شيوعاً التي تعرض معلومات المستخدم أيضاً. # تيك توك تعيد التوجيه من الروابط القصيرة إلى الروابط الطويلة تلقائياً. final_url = f"https://www.tiktok.com/foryou?is_from_webapp=1&sender_device=pc&web_id=7372990422119335456&vid={video_id}" # يمكننا تجربة أيضاً: f"https://www.tiktok.com/embed/v2/{video_id}" أو f"https://www.tiktok.com/share/video/{video_id}" print(f"محاولة جلب بيانات الفيديو من: {final_url}") try: r = requests.get(final_url, impersonate="chrome", timeout=15) r.raise_for_status() # ترفع استثناء لأخطاء HTTP tree = html.fromstring(r.text, parser=html.HTMLParser(encoding="utf8")) # البحث عن السكربت الذي يحتوي على البيانات الأولية # يختلف المسار لبيانات الفيديو عن بيانات المستخدم script_tag = tree.xpath('//script[@id="__UNIVERSAL_DATA_FOR_REHYDRATION__"]') if not script_tag: return ("خطأ: لم يتم العثور على وسم البيانات في الصفحة. " "قد يكون هيكل الصفحة قد تغير، أو تم حظر الطلب.") data = json.loads(script_tag[0].text) # المسار المتوقع لبيانات الفيديو في JSON # هذا المسار يمكن أن يتغير مع تحديثات تيك توك video_data_raw = data.get("__DEFAULT_SCOPE__", {})\ .get("webapp.video-detail", {})\ .get("itemInfo", {})\ .get("itemStruct", {}) if not video_data_raw: return (f"خطأ: لم يتم العثور على تفاصيل للفيديو: '{video_id}'. " "تأكد من صحة الرابط وأن الفيديو متاح للعامة.") # استخلاص البيانات من الكائن المستخرج video_info = { "title": video_data_raw.get("desc", "لا يتوفر عنوان"), "author_username": video_data_raw.get("author", {}).get("uniqueId", "غير معروف"), "author_nickname": video_data_raw.get("author", {}).get("nickname", "غير معروف"), "create_time": datetime.datetime.fromtimestamp(video_data_raw.get("createTime", 0)).strftime('%Y-%m-%d %H:%M:%S') if video_data_raw.get("createTime") else "غير معروف", "play_count": f"{video_data_raw.get('stats', {}).get('playCount', 0):,}", "digg_count": f"{video_data_raw.get('stats', {}).get('diggCount', 0):,}", # الإعجابات "comment_count": f"{video_data_raw.get('stats', {}).get('commentCount', 0):,}", "share_count": f"{video_data_raw.get('stats', {}).get('shareCount', 0):,}", "save_count": f"{video_data_raw.get('stats', {}).get('collectCount', 0):,}", # حفظ الفيديو "cover_url": video_data_raw.get("video", {}).get("cover", {}).get("url_list", [""])[0], "video_url": f"https://www.tiktok.com/@{video_data_raw.get('author', {}).get('uniqueId', 'username')}/video/{video_id}" } # بناء مخرج HTML المنسق output_html = f"""

{video_info['title']}

المستخدم: @{video_info['author_username']} ({video_info['author_nickname']})

تاريخ الإنشاء: {video_info['create_time']}

صورة غلاف الفيديو
{video_info['play_count']} مشاهدة
{video_info['digg_count']} إعجاب
{video_info['comment_count']} تعليق
{video_info['share_count']} مشاركة
{video_info['save_count']} حفظ
مشاهدة الفيديو على تيك توك

⚠️ ملاحظة هامة: البيانات مستخلصة من صفحة تيك توك. هذه الطريقة غير رسمية وغير مستقرة وقد تتوقف عن العمل في أي وقت. استخدم على مسؤوليتك الخاصة ولأغراض تعليمية فقط. لا يمكن لهذا التطبيق كتابة تعليقات.

""" return gr.update(value=output_html, visible=True), gr.update(value="", visible=False) except requests.exceptions.RequestException as e: error_msg = f"خطأ في الاتصال بتيك توك: {e}. قد يكون عنوان IP محظوراً." return gr.update(value="", visible=False), gr.update(value=error_msg, visible=True) except (KeyError, ValueError, IndexError, json.JSONDecodeError) as e: error_msg = f"خطأ في تحليل بيانات الفيديو: {e}. قد يكون هيكل صفحة تيك توك قد تغير." return gr.update(value="", visible=False), gr.update(value=error_msg, visible=True) except Exception as e: error_msg = f"حدث خطأ غير متوقع: {e}. يرجى المحاولة مرة أخرى." return gr.update(value="", visible=False), gr.update(value=error_msg, visible=True) # --- واجهة Gradio --- with gr.Blocks(theme="soft", title="جالب معلومات فيديو تيك توك") as demo: gr.Markdown("# جالب معلومات فيديو تيك توك") gr.Markdown("أدخل رابط فيديو تيك توك (مثال: `https://www.tiktok.com/@username/video/VIDEO_ID`) للحصول على تفاصيله.") with gr.Row(): video_url_input = gr.Textbox(label="رابط فيديو تيك توك", placeholder="مثال: https://www.tiktok.com/@cristiano/video/7300762635957095713", scale=3) submit_button = gr.Button("جلب التفاصيل", scale=1) # مكونات الإخراج output_html_display = gr.HTML(label="تفاصيل الفيديو", visible=False) error_message_display = gr.Markdown(visible=False) # تعريف التفاعل submit_button.click( fn=get_tiktok_video_details, inputs=video_url_input, outputs=[output_html_display, error_message_display] ) if __name__ == "__main__": demo.launch()