File size: 5,402 Bytes
d145b59
 
 
 
 
f55911c
d145b59
 
16bd39e
bf41958
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d145b59
bf41958
 
 
 
 
 
 
 
 
 
908b2dc
8062168
d0cc56e
 
bf41958
d0cc56e
 
 
 
bf41958
 
d0cc56e
bf41958
d0cc56e
 
 
 
908b2dc
bf41958
 
 
 
d145b59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bf41958
 
 
 
 
 
 
 
d145b59
bf41958
d145b59
 
 
 
bf41958
 
 
d145b59
 
 
 
 
 
 
 
bf41958
 
 
 
 
b7b3447
d145b59
b7b3447
d145b59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
908b2dc
d145b59
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/* eslint-disable jsdoc/require-jsdoc */
const axios = require("axios");
const FormData = require("form-data");
const fs = require("fs");
const { exec } = require("child_process");
const path = require("path");

async function ttt(link) {
  try {
    const form = new FormData();
    form.append("url", link);
    form.append("count", "12");
    form.append("cursor", "0");
    form.append("web", "1");
    form.append("hd", "1");

    const { data } = await axios.post("https://www.tikwm.com/api/", form);

    if (data.code === 0 && data.msg === "success") {
      const baseUrl = "https://www.tikwm.com";
      data.data.cover = baseUrl + data.data.cover;
      data.data.play = baseUrl + data.data.play;
      data.data.wmplay = baseUrl + data.data.wmplay;
      data.data.hdplay = baseUrl + data.data.hdplay;
      data.data.music = baseUrl + data.data.music;
      data.data.author.avatar = baseUrl + data.data.author.avatar;
    }

    const res = {
      status: 200,
      type: "tiktok",
      title: data.data?.title || null,
      desc: null,
      thumbnail: data.data.cover,
      video: [{ url: data.data.hdplay }, { url: data.data.play }],
      music: [{ url: data.data.music }],
      image: data.data.images,
    };
    /*
   if (res.image) {
    const outputDir = path.join(__dirname, "../tmp")
    await downloadImages(res.image, outputDir);

    const FNvd = `tt_video_${Date.now()}.mp4`;
    const FNad = `tt_audio_${Date.now()}.mp3`;
    const videoPath = `${outputDir}/${FNvd}`;
    const audioPath = `${outputDir}/${FNad}`;

// βœ… Unduh audio sebelum dipakai
    await downloadAudio(res.music[0].url, audioPath);

    const slideResult = await createSlideshow(outputDir, videoPath, audioPath);
    if (slideResult) {
      res.video.push({ resolusi: "Slideshow", url: `https://fullperr-hutatools.hf.space/tmp/${FNvd}`});
    }
}*/
    return res;
  } catch (e) {
    return { status: 500, message: e.message };
  }
}

async function downloadAudio(audioUrl, outputFile) {
  const response = await axios({
    url: audioUrl,
    responseType: "stream",
  });

  return new Promise((resolve, reject) => {
    const writer = fs.createWriteStream(outputFile);
    response.data.pipe(writer);
    writer.on("finish", () => {
      console.log(`βœ… Audio telah diunduh: ${outputFile}`);
      resolve(outputFile);
    });
    writer.on("error", reject);
  });
}

async function downloadImages(imageUrls, outputDir) {
  if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir);

  let downloadPromises = imageUrls.map((url, index) => {
    const filePath = `${outputDir}/image${index + 1}.jpg`;
    return axios({ url, responseType: "stream" }).then((response) => {
      return new Promise((resolve, reject) => {
        const writer = fs.createWriteStream(filePath);
        response.data.pipe(writer);
        writer.on("finish", resolve);
        writer.on("error", reject);
      });
    });
  });

  await Promise.all(downloadPromises);
  console.log("βœ… Semua gambar telah diunduh.");
}

async function getAudioDuration(audioFile) {
  return new Promise((resolve, reject) => {
    exec(
      `ffprobe -i ${audioFile} -show_entries format=duration -v quiet -of csv="p=0"`,
      (error, stdout) => {
        if (error) {
          reject("❌ Gagal mendapatkan durasi audio.");
          return;
        }
        resolve(parseFloat(stdout.trim()));
      }
    );
  });
}

async function createSlideshow(imagesDir, outputVideo, audioFile) {
  const imageFiles = fs
    .readdirSync(imagesDir)
    .filter((file) => file.endsWith(".jpg"));
  const totalImages = imageFiles.length;

  if (totalImages === 0) {
    console.error("❌ Tidak ada gambar untuk slideshow.");
    return null;
  }

  try {
    let audioDuration = await getAudioDuration(audioFile);
    if (audioDuration > 25) {
      console.log("⏳ Audio lebih dari 25 detik, membatasi ke 25 detik.");
      audioDuration = 25;
    }
    const outputDir = path.join(__dirname, "../tmp")
    const frameDuration = audioDuration / totalImages;
    const tempDirv = `${outputDir}/temp_video_${Date.now()}.mp4`;
    console.log(`πŸ“ Durasi audio: ${audioDuration}s`);
    console.log(`πŸ–Ό Durasi per gambar: ${frameDuration}s`);

    const ffmpegCommand = `ffmpeg -framerate 1/${frameDuration} -i ${imagesDir}/image%d.jpg -filter_complex "pad=iw:ih:(ow-iw)/2:(oh-ih)/2" -r 25 -c:v libx264 -pix_fmt yuv420p ${tempDirv}`;

    console.log("πŸš€ Membuat slideshow...");
    return new Promise((resolve, reject) => {
      exec(ffmpegCommand, (error) => {
        if (error) {
          console.error("❌ Error saat membuat slideshow:", error);
          reject(null);
          return;
        }

        console.log("βœ… Slideshow selesai dibuat.");
        const audioCommand = `ffmpeg -i ${tempDirv} -i ${audioFile} -filter_complex "[1:a]apad" -shortest -c:v libx264 -pix_fmt yuv420p -c:a aac -b:a 128k ${outputVideo}`;

        exec(audioCommand, (audioError) => {
          if (audioError) {
            console.error("❌ Error saat menambahkan audio:", audioError);
            reject(null);
            return;
          }

          console.log("βœ… Video dengan audio selesai dibuat.");
          console.log("🧹 Folder gambar sementara dihapus.");
          resolve(outputVideo); 
        });
      });
    });
  } catch (error) {
    console.error(error);
    return null;
  }
}

module.exports = { ttt };