Compare commits

...

15 commits

Author SHA1 Message Date
axui2 b6bf093734
Merge 5941719ab1 into 080fc043ea 2024-05-01 10:48:56 +03:00
jj 080fc043ea
best audio picking improvements for youtube, tiktok, and soundcloud (#476) 2024-04-30 09:39:32 +02:00
wukko 95925c9864
soundcloud: replace filter with find and clean up 2024-04-30 13:38:01 +06:00
wukko ed8af6ca96
tiktok & soundcloud: proper best audio picking
also improved tiktok audio file naming scheme. full audio now has the "_audio_original" tag. audio extracted from video is simply "_audio".
2024-04-30 13:22:29 +06:00
wukko 276caa011a
youtube: fall back to m4a audio if opus isn't available 2024-04-30 11:24:12 +06:00
axui2 5941719ab1
Merge branch 'wukko:current' into axui2-patch-1 2024-04-26 23:24:08 +03:00
axui2 4a2c0af728
Update ar.json
Signed-off-by: axui2 <143213988+axui2@users.noreply.github.com>
2024-04-26 23:23:15 +03:00
axui2 048366b46b
Update ar.json
Signed-off-by: axui2 <143213988+axui2@users.noreply.github.com>
2024-04-16 14:42:11 +03:00
axui2 590adf257f
Update ar.json
Signed-off-by: axui2 <143213988+axui2@users.noreply.github.com>
2024-04-16 14:30:52 +03:00
axui2 a205589585
Update ar.json
Signed-off-by: axui2 <143213988+axui2@users.noreply.github.com>
2024-04-08 20:43:52 +03:00
axui2 41e51d20e3
Update ar.json
Signed-off-by: axui2 <143213988+axui2@users.noreply.github.com>
2024-04-06 21:02:39 +03:00
axui2 a55291329a
Update ar.json
Signed-off-by: axui2 <143213988+axui2@users.noreply.github.com>
2024-04-06 20:59:00 +03:00
axui2 6175224f5d
Update ar.json
Signed-off-by: axui2 <143213988+axui2@users.noreply.github.com>
2024-04-06 07:28:25 +03:00
axui2 005d76527f
fixed a spacing error
fixed a spacing error

Signed-off-by: axui2 <143213988+axui2@users.noreply.github.com>
2024-04-06 07:02:58 +03:00
axui2 8ed51f2536
Create ar.json
Signed-off-by: axui2 <143213988+axui2@users.noreply.github.com>
2024-04-06 06:50:32 +03:00
6 changed files with 211 additions and 60 deletions

View file

@ -0,0 +1,162 @@
{
"name": "العربية",
"substrings": {
"ContactLink": "تحقق من <a class=\"text-backdrop link\" href=\"{statusPage}\" target=\"_blank\">حالة الموقع</a> أو <a class=\"text-backdrop link\" href=\"https://github.com/wukko/cobalt\" target=\"_blank\">زور صفحتنا في github</a>"
},
"strings": {
"AppTitleCobalt": "كوبالت",
"LinkInput": "إلصق رابط هنا",
"AboutSummary": "كوبالت ليس مثل بقايا مواقع التحميلات الأخرى، لا إعلانات، ولا تتبعات، ولا أي خرابيط. فقط قم بلصق فيديو وسيتم تنزيله على طول!",
"EmbedBriefDescription": "قم بتنزيل ما تحب بدون إعلانات وتتبعات وأي خرابيط غريب ومخادع.",
"MadeWithLove": "برمجة <a class=\"text-backdrop link\" href=\"https://wukko.me\" target=\"_blank\">wukko</a>، ترجمة <a class=\"text-backdrop link\" href=\"https://github.com/axui2\" target=\"_blank\">اياد ابراهيم</a>",
"AccessibilityInputArea": "حقل لصق النص",
"AccessibilityOpenAbout": "فتح نافذة حول",
"AccessibilityDownloadButton": "زر التنزيل",
"AccessibilityOpenSettings": "فتح نافذة الإعدادات",
"AccessibilityOpenDonate": "فتح نافذة التبرع",
"TitlePopupAbout": "ما هو كوبالت؟",
"TitlePopupSettings": "الإعدادات",
"TitlePopupChangelog": "ما الجديد؟",
"TitlePopupDonate": "إدعم كوبالت",
"TitlePopupDownload": "كيفية التنزيل",
"ErrorSomethingWentWrong": "حدث شيء ما خطأ ولا يمكن الحصول على أي شيء لك. حاول مجددا، لكن إذا استمر الخطأ، {ContactLink}.",
"ErrorUnsupported": "يبدو أن الموقع غير معتمد بعد أو الرابط غير متاح. هل أدخلت الرابط الصحيح؟",
"ErrorBrokenLink": "{s} مدعم، لكن هناك شيء ما خطأ في الرابط. هل لصقته كاملاً؟",
"ErrorNoLink": "لا أفهم ماذا تريد تنزيله! رجاءا أعطني رابط :(",
"ErrorPageRenderFail": "اذا تقرأ هذا فهناك خطأ ما في عارض الصفحات. رجاءا {ContactLink}.",
"ErrorRateLimit": "أنت تقوم بطلبات كثيرة جدا. إنتظر لمدة دقيقة!",
"ErrorCouldntFetch": "لم يمكن العثور على أي شيء ما حول هذا الرابط. تأكد من أنه يعمل وحاول مرة أخرى. قد تكون بعض المحتويات محظورة بمنطقتك.",
"ErrorLengthLimit": "لا يمكن تنزيل فيديوهات أكثر من {s} دقائق. إلصق رابط لفيديو مدته أصغر!",
"ErrorBadFetch": "حدث خطأ ما في محاولة جمع معلومات حول الرابط. هل أنت متأكد بأنه يعمل؟ إذا الرابط كذلك فحاول مرة أخرى.",
"ErrorNoInternet": "أنت غير متصل بالإنترنت أو واجهة برمجة التطبيقات لكوبالت غير متاحة مؤقتًا. تحقق من اتصالك وحاول مرة أخرى.",
"ErrorCantConnectToServiceAPI": "لم يمكن الاتصال بواجهة برمجة تطبيقات الخدمة. ربما كان معطلاً، أو تم منع كوبالت عنها.",
"ErrorEmptyDownload": "لا يوجد أي شيء يمكن تنزيله عن طريق هذا الرابط. جرب رابط مختلف!",
"ErrorLiveVideo": "هذا بث! انتظر إلى أن ينتهي البث ثم حاول مجددا.",
"SettingsAppearanceSubtitle": "المظهر",
"SettingsThemeSubtitle": "السمة",
"SettingsFormatSubtitle": "تهيئة",
"SettingsQualitySubtitle": "الجودة",
"SettingsThemeAuto": "تلقائي",
"SettingsThemeLight": "فاتح",
"SettingsThemeDark": "داكن",
"SettingsKeepDownloadButton": "إظهار &gt;&gt; دائمًا",
"AccessibilityKeepDownloadButton": "إظهار زر التنزيل دائما",
"SettingsEnableDownloadPopup": "إسأل كيفية التنزيل",
"AccessibilityEnableDownloadPopup": "اسأل ماذا أفعل مع التنزيلات",
"SettingsQualityDescription": "إذا الجودة المختارة لم يكن متاح ستيم اختيار أقرب جودة.",
"NoScriptMessage": "يستخدم كوبالت جافا سكريبت لطلبات APIوالواجهة التفاعلية. يجب عليك السماح لجافا سكريبت باستخدام هذا الموقع. لا توجد نصوص خبيثة، أوعدك.",
"DownloadPopupDescriptionIOS": "كيف تنزل صور:\n1. أضف <a class=\"text-backdrop link\" href=\"https://www.icloud.com/shortcuts/f030d6062e634c0cbb7abd388891a115\" target=\"_blank\">إختصار حفظ الصور</a>\n2. إضغط زر (مشاركة) فوق هذا النص\n3. إضغط زر (الحفظ للصور) في حقل المشاركة\n\nكيف تنزل ملفات:\n1. أضف <a class=\"text-backdrop link\" href=\"https://www.icloud.com/shortcuts/1f1cf698795b4d22beb05a5b526e869e\" target=\"_blank\">إختصار حفظ الملفات</a>\n2. إضغط زر (مشاركة) فوق هذا النص\n3. إضغط زر (الحفظ للملفات) في حقل المشاركة\n4. حدد مجلد لحفظ الملف فيه ثم إضغط (فتح)\n\nهذان الإختصارتان يُستخدمان فقط في موقع كوبالت.",
"DownloadPopupDescription": "زر التنزيل يفتح علامة تبويب جديدة تحتوي على الملف المطلوب. يمكنك تعطيل هذه النافذة في الإعدادات.",
"ClickToCopy": "إضغط للنسخ",
"Download": "تنزيل",
"CopyURL": "نسخ",
"AboutTab": "حول",
"ChangelogTab": "سجل التغييرات",
"DonationsTab": "التبرعات",
"SettingsVideoTab": "الفيديو",
"SettingsAudioTab": "الصوت",
"SettingsOtherTab": "أخرى",
"ChangelogLastMajor": "الإصدار الحالي والإلتزام",
"AccessibilityModeToggle": "تبديل وضع التنزيل",
"DonateLinksDescription": "هذه هي أفضل طريقة للتبرع إذا كنت تريد مني أن أتلقى تبرعك مباشرةً.",
"SettingsAudioFormatBest": "أفضل",
"SettingsAudioFormatDescription": "عندما نوع (أفضل) محدد، ستحصل على الصوت بنفس الطريقة كما هي من جانب الخدمة. لم يتم إعادة ترميزه. سيتم إعادة ترميز الأنواع الباقية.",
"Keyphrase": "قم بتنزيل ما تحب",
"ErrorPopupCloseButton": "فهمت",
"ErrorLengthAudioConvert": "لا يمكن تحويل صوت أطول من {s} دقائق. إختار تنسيق (أفضل) بالإعدادات إذا لم ترغب بالقيود!",
"SettingsAudioFullTikTok": "الصوت كاملاً",
"SettingsAudioFullTikTokDescription": "يقوم بتنزيل الصوت الأصلي المستخدم في الفيديو دون أي تغييرات إضافية بواسطة مؤلف المنشور.",
"ErrorCantGetID": "لم يمكن الحصول على المعلومات الكامة من الرابط المختصر. تأكد من أنه يعمل أو جرب رابط آخر! اذا استمر المشكلة {ContactLink}"
"ErrorNoVideosInTweet": "لم يمكن العثور على أي محتوى في هذه التغريدة. جرب واحدة أخرى!",
"ImagePickerTitle": "إختر الصور لتنزيلها",
"ImagePickerDownloadAudio": "تنزيل الصوت",
"ImagePickerExplanationPC": "إضغط على صورة بالزر الأيمن بالماوس لتنزيلها",
"ImagePickerExplanationPhone": "إلمس باستمرار على صورة لتنزيلها.",
"ErrorNoUrlReturned": "لم نتلقى على رابط تحميل من الخدمة. هذا لا ينبغي أن يحدث أبدا.",
"ErrorUnknownStatus": "تم تلقي رد لا يمكن معالجته. هذا لا ينبغي أن يحدث أبدا.",
"PasteFromClipboard": "لصق",
"ChangelogOlder": "الإصدارات القديمة",
"ChangelogPressToExpand": "إظهار المزيد",
"Miscellaneous": "أخرى",
"ModeToggleAuto": "تلقائي",
"ModeToggleAudio": "الصوت",
"MediaPickerTitle": "إختر ما تريد حفظه.",
"MediaPickerExplanationPC": "انقر بزر الماوس الأيمن لتنزيل ما تريد.",
"MediaPickerExplanationPhone": "اضغط مع الاستمرار لتنزيل ما تريد.",
"TwitterSpaceWasntRecorded": "لم يتم تسجيل السبيس هذا، لذا لا يوجد شيء لتنزيله. جرب واحدة أخرى!",
"ErrorCantProcess": "لا يمكن معالجة طلبك :(\nيمكنك المحاولة مرة أخرى!",
"ChangelogPressToHide": "إخفاء",
"Donate": "تبرع",
"DonateSub": "ساعد هذا الموقع في البقاء على الإنترنت",
"DonateExplanation": "كوبالت لا يرمي إعلانات في وجهك وبالتالي فهو <span class=\"text-backdrop\">مجاني للجميع</span>. لكن تطوير وصيانة خدمة إعلامية كثيفة يستخدمها أكثر من 350 ألف شخص أمر مكلف للغاية، سواء من حيث الوقت أو المال.\nإذا كان كوبالت قد ساعدك في الماضي وترغب في مساعدته في النمو والتطور، فيمكنك القيام بذلك عن طريق التبرع! من خلال التبرع فإنك تساعد كل من يستخدم كوبالت: المعلمين والطلاب ومنشئي المحتوى والفنانين والمحاضرين وغيرهم الكثير!",
"DonateVia": "التبرع في",
"DonateHireMe": "فيه صيني تزوج صينية جابوا كاسات\nهذا المترجم نكاته سامجة",
"SettingsVideoMute": "إزالة الصوت",
"SettingsVideoMuteExplanation": "يزيل الصوت من الفيديو إن أمكن.",
"ErrorSoundCloudNoClientId": "لم يمكن الحصول على الرمز المؤقت المطلوب لتنزيل الصوت من ساوند كلاود.",
"CollapseServices": "لم يمكن الحصول على الرمز المؤقت المطلوب لتنزيل الصوت من ساوند كلاود.",
"CollapseSupport": "الدعم وكود المصدر",
"CollapsePrivacy": "سياسة الخصوصية",
"ServicesNote": "هذه القائمة لم تنتهي وتستمر بالتحديث بمرور الوقت. تأكد من التحقق منها مرة في كل فترة!",
"FollowSupport": "صفحاتنا في مواقع التواصل الاجتماعي:",
"SourceCode": "الموقع في GitHub:",
"PrivacyPolicy": "سياسة خصوصية كوبالت بسيطة: لن يتم جمع أو تخزين أي بيانات عنك ابدًا وقطعًا.\nما تقوم بتنزيله هو ما يخصك فقط، ولا يخصني أو أي أحد.\n\nإذا كان تنزيلك يتطلب عرض مباشر، فسيتم تشفير و تخزين بعض البيانات التي لا يمكن تتبعها مؤقتًا في ذاكرة الوصول العشوائي (RAM) للخادم. من الضروري أن تعمل هذه الميزة.\n\nيتم تخزين المعلومات المتعلقة بالمحتوى المطلوب لمدة <span class=\"text-backdrop\">90 ثانية</span> ثم تتم إزالتها نهائيًا.\n\nلا يمكن فك تشفير البيانات المخزنة إلا باستخدام مفاتيح تشفير فريدة من رابط تنزيلك، بالإضافة إلى أن لا يتوفر قاعدة بيانات كوبالت الرسمية طريقة لقراءتها خارج وظائف المعالجة.",
"ErrorYTUnavailable": "هذا الفيديو غير متاح. ربما يكون مقيدا لسبب أو لفئة عمرية. جرب واحدة أخرى!",
"ErrorYTTryOtherCodec": "لم يتم العثور على أي شيء لتنزيله باستخدام إعداداتك. جرب برنامج ترميز أو جودة أخرى! في بعض الأحيان تتعلق واجهة برمجة تطبيقات اليوتيوب بشكل غير متوقع. حاول مرة أخرى أو حاول إعدادات أخرى.",
"SettingsCodecSubtitle": "ترميز يوتيوب",
"SettingsCodecDescription": "h264: دعم أفضل للمشغل، لكن الجودة تصل إلى 1080.\nnav1: دعم ضعيف للمشغل، لكنه يدعم 8k و HDR.\nnvp9: عادةً ما يكون أعلى معدل بت، ويحتفظ بمعظم التفاصيل. يدعم 4k و HDR.\nاختر h264 إذا كنت تريد أفضل توافق مع المحرر/المشغل/الوسائط الاجتماعية.",
"SettingsAudioDub": "المقطع الصوتي لليوتيوب",
"SettingsAudioDubDescription": "يحدد المقطع الصوتي الذي سيتم استخدامه. إذا لم يكن المقطع المدبلج متاحًا، فسيتم استخدام لغة الفيديو الأصلية بدلاً من ذلك. \n\nأصلي: يتم استخدام لغة الفيديو الأصلية\n.تلقائي: يتم استخدام لغة المتصفح الافتراضية (ولغة كوبالت كذلك).",
"SettingsDubDefault": "الأصلي",
"SettingsDubAuto": "تلقائي",
"SettingsVimeoPrefer": "vimeo نوع تنزيلات",
"SettingsVimeoPreferDescription": "متقدم: رابط ملف مباشر إلى CDN لـ Vimeo. الجودة القصوى هي 1080p.\nداش: يتم دمج الفيديو والصوت بواسطة الكوبالت في ملف واحد. الجودة القصوى هي 4K.\nاختر (متقدم) إذا كنت تريد أفضل توافق مع المحرر/المشغل/الوسائط الاجتماعية. إذا لم يكن التنزيل التدريجي متاحًا، فسيتم استخدام داش بدلاً من ذلك",
"ShareURL": "مشاركة",
"ErrorTweetUnavailable": " لم يتم العثور على أي شيء عن هذه التغريدة. قد يكون هذا بسبب أن رؤيتها محدودة. جرب واحدة أخرى!",
"ErrorTwitterRIP": "يقوم تويتر بتقييد الوصول إلى أي محتوى للمستخدمين غير المصادق عليهم. مع أن هناك طريقة للحصول على تغريدات منتظمة، إلا أنه للأسف من المستحيل الحصول على السبيسات في هذا الوقت. أنا أبحث في حلول ممكنة.",
"PopupCloseDone": "تم",
"Accessibility": "تسهيلات الوصول",
"SettingsReduceTransparency": "إزالة الشفافية",
"SettingsDisableAnimations": "إزالة الرسوم المتحركة",
"FeatureErrorGeneric": "متصفحك لا يسمح أو يدعم هذه الميزة. تحقق عندما يكون هناك أي تحديثات متاحة وحاول مرة أخرى!",
"ClipboardErrorFirefox": "أنت تستخدم فيرفوكس حيث تم تعطيل جميع وظائف قراءة الحافظة. يمكنك اصلاح ذلك من خلال الدخول إلى <a class=\"text-backdrop link\" href=\"{repo}/blob/current/docs/troubleshooting.md#how-to-fix-clipboard-pasting-in-firefox\" target=\"_blank\">هذا الرابط!</a>",
"ClipboardErrorNoPermission": "لا يستطيع كوبالت الوصول إلى أحدث عنصر في حافظتك دون إذنك. إذا كنت لا تريد منح حق الوصول، فما عليك سوى لصق الرابط يدويًا بدلاً من ذلك. إذا قمت بذلك، فانتقل إلى إعدادات الموقع وقم بتمكين إذن الحافظة.",
"SupportSelfTroubleshooting": "تواجه مشكلة؟ جرب هذه الحلول أولاً:",
"AccessibilityGoBack": "ارجع للخلف وأغلق النافذة",
"CollapseKeyboard": "اختصارات لوحة المفاتيح",
"KeyboardShortcutsIntro": " استخدم الكوبالت بشكل أسرع باستخدام هذه الاختصارات:",
"KeyboardShortcutQuickPaste": "لصق الرابط",
"KeyboardShortcutClear": "مسح منطقة إدخال الرابط",
"KeyboardShortcutClosePopup": "إغلاق كل النوافذ",
"CollapseLegal": "الأحكام والشروط",
"FairUse": "كوبالت أداة تسهل تنزيل محتوى في الإنترنت وتستخدم وكيل محدد فلا يُخزن أي محتوى. \n\nأنت مسؤول عما تقوم بتنزيله، وكيفية استخدامك لهذا المحتوى وتوزيعه. يرجى الانتباه عند استخدام محتوى من الآخرين ونسب الفضل دائمًا إلى منشئين المحتوى الأصليين. \n\nعند استخدامها لأغراض تعليمية (محاضرة، واجبات منزلية، الخ) يرجى إرفاق رابط المصدر.",
"SettingsDisableMetadata": "عدم إضافة بيانات وصفية",
"NewDomainWelcomeTitle": "أهلاً بك!",
"DataTransferSuccess": "لعلمك، تم نقل إعداداتك تلقائيًا :)",
"DataTransferError": "حدث خطأ ما أثناء نقل إعداداتك. يجب عليك فتح الإعدادات ثم تغييرها.",
"SupportNotAffiliated": "كوبالت لا ينتسب لهذه المواقع أعلاه",
"SponsoredBy": "برعاية",
"FilenameTitle": "مظهر عنوان الملف",
"FilenamePatternClassic": "كلاسيكي",
"FilenamePatternPretty": "جميل",
"FilenamePatternBasic": "أساسي",
"FilenamePatternNerdy": "مربط",
"FilenameDescription": "كلاسيكي: نمط إسم الملف الافتراضي \nأساسي: المعلومات الأساسية بين قوسين\nجميل: معلومات بين قوسين\nمربط: جميع المعلومات بين قوسين\n\nبعض الخدمات لا تدعم إعداداتك لإسم الملفات ودائمًا تستخدم الخيار الأصلي.",
"Preview": "معاينة",
"FilenamePreviewVideoTitle": "عنوان الفيديو",
"FilenamePreviewAudioTitle": "عنوان الصوت",
"FilenamePreviewAudioAuthor": "مؤدي الصوت",
"StatusPage": "صفحة حالة الخدمة",
"TroubleshootingGuide": "دليل إستكشاف الأخطاء وإصلاحها",
"DonateImageDescription": "مدري والله لا تسألني",
"SettingsTwitterGif": "تحويل صور gif إلى .gif",
"SettingsTwitterGifDescription": "يؤدي تحويل فيديو متكرر لـ GIF بتقليل الجودة وزيادة حجم الملف. إذا تريد كفاءة ممتازة فلا تفَعِّل هذا.",
"ErrorTweetNSFW": "عيب يا ولد ترا الله يشوفك",
"ErrorTweetProtected": "هذه التغريدة من حساب خاص، لذا لا يمكن تحميله. جرب واحدة أخرى!",
"UpdateEncryption": "التشفير والخدمات الجديدة",
"PrivateAnalytics": "التحليلات الخاصة",
"SettingsDisableAnalytics": "إلغاء الاشتراك من التحليلات الخاصة",
"SettingsAnalyticsExplanation": "فَعِّل هذا الخيار إذا كنت لا تريد أن تتضمن في إحصائيات حركة المرور المجهولة عبر الانترنت. هذا الموقع لن يتم تتبعك أو تخزين معلوماتك، ولا يستخدم ملفات تعريف الارتباط.",
"AnalyticsDescription": "يستخدم كوبالت موقع plausible المستضاف ذاتيًا للحصول على رقم تقريبي لعدد مستخدمو هذا الموقع. \n\nيتوافق plausible تمامًا مع الهيئة الوطنية للأمن السيبراني ولا يستخدم ملفات تعريف الارتباط ولا يخزن أي معلومات يمكن التعرف عليها، ولا حتى عنوانك الـ IP. \n\nلا يتم حفظ أي شيء عما تقوم بتنزيله في أي مكان. يتم استخدامه فقط لإحصائيات حركة المرور المجهولة عبر الإنترنت، لا أكثر. \n\nموقع plausible مفتوح المصدر بالكامل، تمامًا مثل كوبالت، وإذا كنت ترغب في معرفة المزيد عنه، يمكنك القيام بذلك <a class=\"text-backdrop link\" href=\"https://plausible.io\" target=\"_blank\">هنا</a>. إذا كنت ترغب في إلغاء الاشتراك في إحصائيات حركة المرور عبر الإنترنت، يمكنك القيام بذلك في الإعدادات > أخرى."
}
}

View file

@ -137,40 +137,22 @@ export default function(r, host, userFormat, isAudioOnly, lang, isAudioMuted, di
audioFormat = "best"
}
const serviceBestAudio = r.bestAudio || services[host]["bestAudio"];
const isBestAudio = audioFormat === "best";
const isBestOrMp3 = audioFormat === "mp3" || isBestAudio;
const isBestAudioDefined = isBestAudio && services[host]["bestAudio"];
const isBestHostAudio = services[host]["bestAudio"] && (audioFormat === services[host]["bestAudio"]);
const isBestOrMp3 = isBestAudio || audioFormat === "mp3";
const isBestAudioDefined = isBestAudio && serviceBestAudio;
const isBestHostAudio = serviceBestAudio && (audioFormat === serviceBestAudio);
const isTikTok = host === "tiktok" || host === "douyin";
const isTumblrAudio = host === "tumblr" && !r.filename;
const isSoundCloud = host === "soundcloud";
if (isTikTok && services.tiktok.audioFormats.includes(audioFormat)) {
if (r.isMp3 && isBestOrMp3) {
audioFormat = "mp3";
processType = "bridge"
} else if (isBestAudio) {
audioFormat = "m4a";
processType = "bridge"
}
}
if (isSoundCloud && services.soundcloud.audioFormats.includes(audioFormat)) {
if (r.isMp3 && isBestOrMp3) {
audioFormat = "mp3";
processType = "render"
copy = true
} else if (isBestAudio || audioFormat === "opus") {
audioFormat = "opus";
processType = "render"
copy = true
}
}
if (isBestAudioDefined || isBestHostAudio) {
audioFormat = services[host]["bestAudio"];
audioFormat = serviceBestAudio;
processType = "bridge";
if (isSoundCloud) {
processType = "render"
copy = true
}
} else if (isBestAudio && !isSoundCloud) {
audioFormat = "m4a";
copy = true

View file

@ -4,7 +4,7 @@ import { cleanString } from "../../sub/utils.js";
const cachedID = {
version: '',
id: ''
};
}
async function findClientID() {
try {
@ -32,9 +32,7 @@ async function findClientID() {
cachedID.id = clientid;
return clientid;
} catch (e) {
return false;
}
} catch {}
}
export default async function(obj) {
@ -58,27 +56,30 @@ export default async function(obj) {
let json = await fetch(`https://api-v2.soundcloud.com/resolve?url=${link}&client_id=${clientId}`).then((r) => {
return r.status === 200 ? r.json() : false
}).catch(() => { return false });
}).catch(() => {});
if (!json) return { error: 'ErrorCouldntFetch' };
if (!json["media"]["transcodings"]) return { error: 'ErrorEmptyDownload' };
let isMp3,
selectedStream = json.media.transcodings.filter(v => v.preset === "opus_0_0")
let bestAudio = "opus",
selectedStream = json.media.transcodings.find(v => v.preset === "opus_0_0");
// fall back to mp3 if no opus is available
if (selectedStream.length === 0) {
selectedStream = json.media.transcodings.filter(v => v.preset === "mp3_0_0")
isMp3 = true
selectedStream = json.media.transcodings.find(v => v.preset === "mp3_0_0");
bestAudio = "mp3"
}
let fileUrlBase = selectedStream[0]["url"];
let fileUrlBase = selectedStream.url;
let fileUrl = `${fileUrlBase}${fileUrlBase.includes("?") ? "&" : "?"}client_id=${clientId}&track_authorization=${json.track_authorization}`;
if (fileUrl.substring(0, 54) !== "https://api-v2.soundcloud.com/media/soundcloud:tracks:") return { error: 'ErrorEmptyDownload' };
if (json.duration > maxVideoDuration) return { error: ['ErrorLengthAudioConvert', maxVideoDuration / 60000] };
if (json.duration > maxVideoDuration)
return { error: ['ErrorLengthAudioConvert', maxVideoDuration / 60000] };
let file = await fetch(fileUrl).then(async (r) => { return (await r.json()).url }).catch(() => { return false });
let file = await fetch(fileUrl).then(async (r) => { return (await r.json()).url }).catch(() => {});
if (!file) return { error: 'ErrorCouldntFetch' };
let fileMetadata = {
@ -94,7 +95,7 @@ export default async function(obj) {
title: fileMetadata.title,
author: fileMetadata.artist
},
isMp3,
bestAudio,
fileMetadata
}
}

View file

@ -41,8 +41,9 @@ export default async function(obj) {
detail = detail?.aweme_list?.find(v => v.aweme_id === postId);
if (!detail) return { error: 'ErrorCouldntFetch' };
let video, videoFilename, audioFilename, isMp3, audio, images,
filenameBase = `tiktok_${detail.author.unique_id}_${postId}`;
let video, videoFilename, audioFilename, audio, images,
filenameBase = `tiktok_${detail.author.unique_id}_${postId}`,
bestAudio = 'm4a';
images = detail.image_post_info?.images;
@ -56,12 +57,12 @@ export default async function(obj) {
} else {
let fallback = playAddr.url_list[0];
audio = fallback;
audioFilename = `${filenameBase}_audio_fv`; // fv - from video
audioFilename = `${filenameBase}_audio`;
if (obj.fullAudio || fallback.includes("music")) {
audio = detail.music.play_url.url_list[0]
audioFilename = `${filenameBase}_audio`
audioFilename = `${filenameBase}_audio_original`
}
if (audio.slice(-4) === ".mp3") isMp3 = true;
if (audio.slice(-4) === ".mp3") bestAudio = 'mp3';
}
if (video) return {
@ -72,7 +73,7 @@ export default async function(obj) {
urls: audio,
audioFilename: audioFilename,
isAudioOnly: true,
isMp3: isMp3
bestAudio
}
if (images) {
let imageLinks = [];
@ -86,13 +87,13 @@ export default async function(obj) {
urls: audio,
audioFilename: audioFilename,
isAudioOnly: true,
isMp3: isMp3
bestAudio
}
}
if (audio) return {
urls: audio,
audioFilename: audioFilename,
isAudioOnly: true,
isMp3: isMp3
bestAudio
}
}

View file

@ -4,7 +4,7 @@ import { cleanString } from '../../sub/utils.js';
const yt = await Innertube.create();
const c = {
const codecMatch = {
h264: {
codec: "avc1",
aCodec: "mp4a",
@ -23,8 +23,8 @@ const c = {
}
export default async function(o) {
let info, isDubbed,
quality = o.quality === "max" ? "9000" : o.quality; // 9000(p) - max quality
let info, isDubbed, format = o.format || "h264";
let quality = o.quality === "max" ? "9000" : o.quality; // 9000(p) - max quality
function qual(i) {
if (!i.quality_label) {
@ -56,10 +56,16 @@ export default async function(o) {
let bestQuality, hasAudio;
let adaptive_formats = info.streaming_data.adaptive_formats.filter(e =>
e.mime_type.includes(c[o.format].codec) || e.mime_type.includes(c[o.format].aCodec)
const filterByCodec = (formats) => formats.filter(e =>
e.mime_type.includes(codecMatch[format].codec) || e.mime_type.includes(codecMatch[format].aCodec)
).sort((a, b) => Number(b.bitrate) - Number(a.bitrate));
let adaptive_formats = filterByCodec(info.streaming_data.adaptive_formats);
if (adaptive_formats.length === 0 && format === "vp9") {
format = "h264"
adaptive_formats = filterByCodec(info.streaming_data.adaptive_formats)
}
bestQuality = adaptive_formats.find(i => i.has_video);
hasAudio = adaptive_formats.find(i => i.has_audio);
@ -105,14 +111,15 @@ export default async function(o) {
isAudioOnly: true,
urls: audio.decipher(yt.session.player),
filenameAttributes: filenameAttributes,
fileMetadata: fileMetadata
fileMetadata: fileMetadata,
bestAudio: format === "h264" ? 'm4a' : 'opus'
}
const matchingQuality = Number(quality) > Number(bestQuality) ? bestQuality : quality,
checkSingle = i => qual(i) === matchingQuality && i.mime_type.includes(c[o.format].codec),
checkSingle = i => qual(i) === matchingQuality && i.mime_type.includes(codecMatch[format].codec),
checkRender = i => qual(i) === matchingQuality && i.has_video && !i.has_audio;
let match, type, urls;
if (!o.isAudioOnly && !o.isAudioMuted && o.format === 'h264') {
if (!o.isAudioOnly && !o.isAudioMuted && format === 'h264') {
match = info.streaming_data.formats.find(checkSingle);
type = "bridge";
urls = match?.decipher(yt.session.player);
@ -128,8 +135,8 @@ export default async function(o) {
if (match) {
filenameAttributes.qualityLabel = match.quality_label;
filenameAttributes.resolution = `${match.width}x${match.height}`;
filenameAttributes.extension = c[o.format].container;
filenameAttributes.youtubeFormat = o.format;
filenameAttributes.extension = codecMatch[format].container;
filenameAttributes.youtubeFormat = format;
return {
type,
urls,

View file

@ -57,7 +57,6 @@
"alias": "tiktok videos, photos & audio",
"patterns": [":user/video/:postId", ":id", "t/:id", ":user/photo/:postId"],
"subdomains": ["vt", "vm"],
"audioFormats": ["best", "m4a", "mp3"],
"enabled": true
},
"douyin": {
@ -74,7 +73,6 @@
"soundcloud": {
"patterns": [":author/:song/s-:accessKey", ":author/:song", ":shortLink"],
"subdomains": ["on", "m"],
"audioFormats": ["best", "opus", "mp3"],
"enabled": true
},
"instagram": {