JerryCoderr

Yt-Downloader

Jul 30th, 2025 (edited)
25
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.56 KB | Source Code | 0 0
  1. export default async function ytDownload(request) {
  2. const { searchParams } = new URL(request.url);
  3. const url = searchParams.get('url');
  4.  
  5. if (!url || !url.includes('youtube.com') && !url.includes('youtu.be')) {
  6. return new Response(JSON.stringify({ error: 'Missing or invalid YouTube URL' }), {
  7. status: 400,
  8. headers: { 'Content-Type': 'application/json' },
  9. });
  10. }
  11.  
  12. const extractVideoId = (url) => {
  13. const match = url.match(/(?:v=|\/)([0-9A-Za-z_-]{11})/);
  14. return match ? match[1] : null;
  15. };
  16.  
  17. const videoId = extractVideoId(url);
  18. let mp3Url = null;
  19. let duration = null;
  20. let title = null;
  21. let thumbnail = null;
  22. let mp4 = null;
  23.  
  24. try {
  25. // Step 1: yt1s.click MP3
  26. const form = new URLSearchParams();
  27. form.append('q', url);
  28. form.append('type', 'mp3');
  29.  
  30. const res = await fetch('https://yt1s.click/search', {
  31. method: 'POST',
  32. headers: {
  33. 'Content-Type': 'application/x-www-form-urlencoded',
  34. 'Origin': 'https://yt1s.click',
  35. 'Referer': 'https://yt1s.click/',
  36. 'User-Agent': 'Mozilla/5.0'
  37. },
  38. body: form
  39. });
  40.  
  41. const text = await res.text();
  42. const match = text.match(/href="(\/download[^"]+)"/);
  43. if (match) {
  44. mp3Url = `https://yt1s.click${match[1]}`;
  45. } else {
  46. // Step 2: flvto fallback
  47. const payload = {
  48. fileType: 'MP3',
  49. id: videoId
  50. };
  51.  
  52. const flvtoRes = await fetch('https://ht.flvto.online/converter', {
  53. method: 'POST',
  54. headers: {
  55. 'Content-Type': 'application/json',
  56. 'Origin': 'https://ht.flvto.online',
  57. 'Referer': `https://ht.flvto.online/widget?url=https://www.youtube.com/watch?v=${videoId}`,
  58. 'User-Agent': 'Mozilla/5.0',
  59. },
  60. body: JSON.stringify(payload)
  61. });
  62.  
  63. const flvtoData = await flvtoRes.json();
  64. if (flvtoData?.link) {
  65. mp3Url = flvtoData.link;
  66. duration = flvtoData.duration || null;
  67. }
  68. }
  69. } catch (e) {
  70. mp3Url = null;
  71. }
  72.  
  73. try {
  74. // Step 3: Clipto for MP4 and metadata
  75. const csrfres = await fetch('https://www.clipto.com/api/csrf', {
  76. headers: {
  77. 'user-agent': 'Mozilla/5.0',
  78. 'referer': 'https://www.clipto.com/id/media-downloader/youtube-downloader'
  79. }
  80. });
  81.  
  82. const csrfData = await csrfres.json();
  83. const csrftoken = csrfData.token;
  84. const kuki = `XSRF-TOKEN=${csrftoken}`;
  85.  
  86. const cliptoRes = await fetch('https://www.clipto.com/api/youtube', {
  87. method: 'POST',
  88. headers: {
  89. 'x-xsrf-token': csrftoken,
  90. 'cookie': kuki,
  91. 'origin': 'https://www.clipto.com',
  92. 'referer': 'https://www.clipto.com/id/media-downloader/youtube-downloader',
  93. 'content-type': 'application/json',
  94. 'user-agent': 'Mozilla/5.0'
  95. },
  96. body: JSON.stringify({ url })
  97. });
  98.  
  99. const data = await cliptoRes.json();
  100. title = data.title;
  101. thumbnail = data.thumbnail;
  102. if (!duration && data.duration) {
  103. duration = data.duration;
  104. }
  105.  
  106. const mp4WithAudio = data.medias.find(v =>
  107. v.ext === 'mp4' && (v.is_audio === true || v.audioQuality)
  108. );
  109. if (mp4WithAudio) {
  110. mp4 = mp4WithAudio.url;
  111. }
  112.  
  113. } catch (err) {
  114. // fallback failed
  115. }
  116.  
  117. const result = {
  118. title,
  119. thumbnail,
  120. mp4,
  121. mp3: mp3Url,
  122. duration: duration ? Math.round(duration) + 's' : null
  123. };
  124.  
  125. return new Response(JSON.stringify(result, null, 2), {
  126. headers: { 'Content-Type': 'application/json' }
  127. });
  128. }
Advertisement
Add Comment
Please, Sign In to add comment