Skip to content

Commit 2946303

Browse files
committed
Fix View, and Downloader
1 parent 2341db9 commit 2946303

File tree

2 files changed

+2
-2
lines changed

2 files changed

+2
-2
lines changed

SHPBOT.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

library/streamer.cjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
const{mkdirSync:mkdirSync}=require("fs"),chalk=require("chalk"),path=require("path");let ffmpegProcess=null;function decodeUnicode(e){return e.replace(/\\u([\d\w]{4})/gi,((e,t)=>String.fromCharCode(parseInt(t,16))))}const processVideo=async({liveUrl:e,rtmpServer:t=null,rtmpKey:r=null,isInfiniteMode:o=!1,streamDuration:a=0,baseFilePath:s="",mode:i="stream"})=>{console.log(chalk.blue("Starting the streaming process. Please wait..."));const n=require("child_process"),{existsSync:l}=require("fs");let c,d=null;"restream"===i?t&&r?(c=`${t}${r}`,d=`${s}.flv`):c=`${s}.flv`:c=`${t}${r}`;const generateFileName=(e,t)=>{let r=0,o=`${e}${r>0?`-${r}`:""}.${t}`;for(;l(o);)r++,o=`${e}${r>0?`-${r}`:""}.${t}`;return o};if(d&&l(d)&&(d=generateFileName(s,"flv")),l(c)){const e=c.split(".").pop();c=generateFileName(s,e)}process.stdout.clearLine(0),process.stdout.cursorTo(0);const p=[chalk.white("Live Url : ")+chalk.red(`${e}`),chalk.white("Output Destination : ")+chalk.yellow(`${c}`),chalk.white("Secondary Output : ")+chalk.green(`${d||"Not Applicable"}`)].join("\n"),m=Math.max(0,p.length-chalk.reset(p).length+20),u=chalk.blue("=".repeat(m));process.stdout.write(`${u}\n${p}\n${u}`);const h=["-re","-stream_loop","-1","-i",e,"-r","30","-b:v","2000k","-c:v","libx264","-preset","veryfast","-c:a","aac","-f","flv","-loglevel","info","-hide_banner",c];d&&h.push(d),a>0&&h.push("-t",a.toString()),ffmpegProcess=n.spawn("ffmpeg",h);let S=0,f=0,g=0,k=0,w=a>0?new Date(Date.now()+1e3*a).toLocaleTimeString():"N/A";ffmpegProcess.stderr.on("data",(e=>{const t=e.toString(),r=t.match(/Duration: (\d{2}):(\d{2}):(\d{2})\.\d{2},/),o=t.match(/time=(\d{2}):(\d{2}):(\d{2})\.\d{2}/),s=t.match(/size=\s*(\d+)kB/);r&&(f=3600*parseInt(r[1])+60*parseInt(r[2])+parseInt(r[3])),o&&(g=3600*parseInt(o[1])+60*parseInt(o[2])+parseInt(o[3]),a>0&&g>=a&&(console.log(chalk.green("\nStream duration reached. Stopping...")),ffmpegProcess.kill("SIGKILL"))),s&&(k=parseInt(s[1]));const i=a>0?(g/a*100).toFixed(2):"N/A",n=(k/1024).toFixed(2),l=new Date(1e3*g).toISOString().substr(11,8);process.stdout.clearLine(0),process.stdout.cursorTo(0),process.stdout.write(chalk.green(`Progress: [${i}%] | Time Elapsed: ${l} | Downloaded: ${n} MB | Estimated End Time: ${w}`)),t.includes("error")&&(S+=1,S>5&&(console.log(chalk.red("\nWe encountered a problem and need to stop. Please try again.")),ffmpegProcess.kill("RESTART")))})),ffmpegProcess.on("close",((n,l)=>{const c=`Streaming process exited with code: ${n} and signal: ${l}`;0!==n&&"SIGINT"!==l&&"SIGKILL"!==l?(console.log(chalk.magenta(c)),console.log(chalk.yellow("The streaming process has ended unexpectedly. Attempting to restart...")),setTimeout((()=>{const n={liveUrl:o||"restream"===i?d:e,rtmpServer:t,rtmpKey:r,isInfiniteMode:o,streamDuration:a,baseFilePath:s};"restream"!==i&&(n.mode=i),processVideo(n)}),3e3)):"SIGINT"===l||"SIGKILL"===l?(console.log(chalk.yellow("Streaming process was automatically terminated. Thankyou!")),process.exit()):console.log(chalk.green("Streaming completed successfully."))})),process.on("SIGINT",(()=>{console.log(chalk.magenta("Streaming has been stopped. Thank you for using our service.")),ffmpegProcess&&ffmpegProcess.kill("SIGINT"),process.exit()}))},reStreamShopee=async({videoUrl:e,rtmpServer:t=null,rtmpKey:r=null,isInfiniteMode:o=!1,streamDuration:a=0})=>new Promise((async(s,i)=>{try{let s=null,i=`${__dirname}/../${e}`,n="stream";if(!e.includes("mp4")&&!e.includes("flv")){if(s=await getShopeeStreamDetails(e),!s)throw new Error("Stream details could not be retrieved.");i=decodeURIComponent(s.play_url),n="restream"}const l=`${__dirname}/../stream_output/${s?.room_id}-${s?.username}`;await processVideo({liveUrl:i,rtmpServer:t,rtmpKey:r,isInfiniteMode:o,streamDuration:a,baseFilePath:l,mode:n})}catch(e){i(e),console.error("Error in reStreamShopee function: ",e)}})),downloadStream=async({videoUrl:e,durasiVideo:t=0,rtmpServer:r=null,rtmpKey:o=null,isInfinite:a=!1})=>{try{const s=getStreamProvider(e);let i=null;switch(s){case"shopee":case"filestream":i=await reStreamShopee({videoUrl:e,streamDuration:t?60*t:null,rtmpServer:r,rtmpKey:o,isInfiniteMode:a});break;case"tiktok":i=await tiktokDownload({videoUrl:e,duration:t?60*parseInt(t):null,rtmpServer:r,rtmpKey:o,isInfiniteMode:a});break;default:throw Error(`Platform "${s}" Not Supported Yet!`)}return i}catch(e){throw Error(e)}},getStreamProvider=e=>{let t="";return t=e.includes("http")?new URL(e).hostname:"filestream",t.includes("tiktok")?"tiktok":t.includes("youtube")?"youtube":t.includes("twitch")?"twitch":t.includes("facebook")?"facebook":t.includes("tokopedia")?"tokopedia":t.includes("shopee")?"shopee":t.includes("file")?"filestream":t},getShopeeStreamDetails=async e=>{const t=new URL(e),r=t.hostname,o=t.searchParams.get("session");return fetch(`https://${r}/api/v1/session/${o}`,{headers:{Host:`${r}`,"Sec-Ch-Ua":'"Brave";v="119", "Chromium";v="119", "Not?A_Brand";v="24"',"Sec-Ch-Ua-Mobile":"?0","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","X-Api-Source":"pc","Content-Type":"application/json",Accept:"application/json","X-Shopee-Language":"id","X-Requested-With":"XMLHttpRequest","Sec-Ch-Ua-Platform":'"macOS"',"Sec-Gpc":"1","Accept-Language":"id-ID,id;q=0.6","Sec-Fetch-Site":"same-origin","Sec-Fetch-Mode":"cors","Sec-Fetch-Dest":"empty",Referer:`https://${r}/?is_from_login=true&is_from_login=true`,"Accept-Encoding":"gzip, deflate, br"}}).then((async e=>{const t=await e.json();return 0==t.err_code?t?.data?.session:t}))},tiktokStreamData=async e=>{const t=`https://www.tiktok.com/@${e}/live`,r=(await fetch(t,{headers:{"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"}}).then((e=>e.text()))).match(/room_id=(\d+)/);if(!r)throw new Error("No live stream found");const o=r[1];console.info(`\nFound live stream with room id ${o}!`);const a=`https://www.tiktok.com/api/live/detail/?aid=1988&roomID=${o}`,{LiveRoomInfo:s}=await fetch(a).then((e=>e.json())),{title:i,liveUrl:n}=s;return{title:i,liveUrl:n}},tiktokDownload=async({videoUrl:e,outputDirectory:t="stream_output",format:r="mp4",duration:o=0,rtmpKey:a=null,rtmpServer:s=null,isInfiniteMode:i=!1})=>new Promise((async(n,l)=>{try{const n=e.split("/"),l=n[n.length-2].replace("@",""),{title:c,liveUrl:d}=await tiktokStreamData(l),p=t.endsWith(r)?t:`${t.replace(/\/$/,"")}/${l}-${Date.now()}.${r}`;mkdirSync(path.dirname(p),{recursive:!0}),await processVideo({liveUrl:d,rtmpServer:s,rtmpKey:a,isInfiniteMode:i,streamDuration:o,baseFilePath:p,mode:"restream"}),console.info("\nCtrl+C to stop downloading and exit")}catch(e){l(e)}}));module.exports={ffmpegProcess:ffmpegProcess,reStreamShopee:reStreamShopee,getShopeeStreamDetails:getShopeeStreamDetails,downloadStream:downloadStream,decodeUnicode:decodeUnicode,tiktokDownload:tiktokDownload};
1+
const{mkdirSync:mkdirSync}=require("fs"),chalk=require("chalk"),path=require("path"),fs=require("fs"),axios=require("axios"),{performance:performance}=require("perf_hooks");let ffmpegProcess=null;function decodeUnicode(e){return e.replace(/\\u([\d\w]{4})/gi,((e,t)=>String.fromCharCode(parseInt(t,16))))}async function downloadFile(e,t,o=30){const r=fs.createWriteStream(t),a=performance.now(),n=a+1e3*o,s=new Date(Date.now()+1e3*o).toLocaleTimeString(),i=await axios({url:e,method:"GET",responseType:"stream"});i.headers["content-length"]&&parseInt(i.headers["content-length"],10);let l=0;i.data.on("data",(e=>{l+=e.length;const t=(performance.now()-a)/1e3,o=t/(n/1e3)*100,r=l/1048576;process.stdout.clearLine(),process.stdout.cursorTo(0),process.stdout.write(`Progress: [${o.toFixed(2)}%] | Time Elapsed: ${formatTime(t)} | Downloaded: ${r.toFixed(2)} MB | Estimated End Time: ${s}`)})),i.data.pipe(r);const c=setTimeout((()=>{r.end(),console.log(`\nDownload stopped after ${o} minutes`)}),60*o*1e3);return new Promise(((e,t)=>{r.on("finish",(()=>{clearTimeout(c),e()})),r.on("error",(e=>{clearTimeout(c),t(e)}))}))}function formatTime(e){const t=Math.floor(e/3600),o=Math.floor(e%3600/60),r=Math.floor(e%60);return`${t.toString().padStart(2,"0")}:${o.toString().padStart(2,"0")}:${r.toString().padStart(2,"0")}`}const processVideo=async({liveUrl:e,rtmpServer:t=null,rtmpKey:o=null,isInfiniteMode:r=!1,streamDuration:a=0,baseFilePath:n="",mode:s="stream"})=>{console.log(chalk.blue("Starting the streaming process. Please wait..."));const i=require("child_process"),{existsSync:l}=require("fs");let c,d=null;"restream"===s?t&&o?(c=`${t}${o}`,d=`${n}.flv`):c=`${n}.flv`:c=`${t}${o}`;const generateFileName=(e,t)=>{let o=0,r=`${e}${o>0?`-${o}`:""}.${t}`;for(;l(r);)o++,r=`${e}${o>0?`-${o}`:""}.${t}`;return r};if(d&&l(d)&&(d=generateFileName(n,"flv")),l(c)){const e=c.split(".").pop();c=generateFileName(n,e)}process.stdout.clearLine(0),process.stdout.cursorTo(0);const p=[chalk.white("Live Url : ")+chalk.red(`${e}`),chalk.white("Output Destination : ")+chalk.yellow(`${c}`),chalk.white("Secondary Output : ")+chalk.green(`${d||"Not Applicable"}`)].join("\n"),m=Math.max(0,p.length-chalk.reset(p).length+20),u=chalk.blue("=".repeat(m));process.stdout.write(`${u}\n${p}\n${u}`);const h=["-re","-stream_loop","-1","-i",e,"-r","30","-b:v","2000k","-c:v","libx264","-preset","veryfast","-c:a","aac","-f","flv","-loglevel","info","-hide_banner",c];d&&h.push(d),a>0&&h.push("-t",a.toString()),ffmpegProcess=i.spawn("ffmpeg",h);let f=0,S=0,g=0,w=0,k=a>0?new Date(Date.now()+1e3*a).toLocaleTimeString():"N/A";ffmpegProcess.stderr.on("data",(e=>{const t=e.toString(),o=t.match(/Duration: (\d{2}):(\d{2}):(\d{2})\.\d{2},/),r=t.match(/time=(\d{2}):(\d{2}):(\d{2})\.\d{2}/),n=t.match(/size=\s*(\d+)kB/);o&&(S=3600*parseInt(o[1])+60*parseInt(o[2])+parseInt(o[3])),r&&(g=3600*parseInt(r[1])+60*parseInt(r[2])+parseInt(r[3]),a>0&&g>=a&&(console.log(chalk.green("\nStream duration reached. Stopping...")),ffmpegProcess.kill("SIGKILL"))),n&&(w=parseInt(n[1]));const s=a>0?(g/a*100).toFixed(2):"N/A",i=(w/1024).toFixed(2),l=new Date(1e3*g).toISOString().substr(11,8);process.stdout.clearLine(0),process.stdout.cursorTo(0),process.stdout.write(chalk.green(`Progress: [${s}%] | Time Elapsed: ${l} | Downloaded: ${i} MB | Estimated End Time: ${k}`)),t.includes("error")&&(f+=1,f>5&&(console.log(chalk.red("\nWe encountered a problem and need to stop. Please try again.")),ffmpegProcess.kill("RESTART")))})),ffmpegProcess.on("close",((i,l)=>{const c=`Streaming process exited with code: ${i} and signal: ${l}`;0!==i&&"SIGINT"!==l&&"SIGKILL"!==l?(console.log(chalk.magenta(c)),console.log(chalk.yellow("The streaming process has ended unexpectedly. Attempting to restart...")),setTimeout((()=>{"restream"!==s&&({liveUrl:r||"restream"===s?d:e,rtmpServer:t,rtmpKey:o,isInfiniteMode:r,streamDuration:a,baseFilePath:n}.mode=s),downloadFile(e,n,a).then((()=>console.log("Download complete"))).catch((e=>console.error("Download failed",e)))}),3e3)):"SIGINT"===l||"SIGKILL"===l?(console.log(chalk.yellow("Streaming process was automatically terminated. Thankyou!")),process.exit()):console.log(chalk.green("Streaming completed successfully."))})),process.on("SIGINT",(()=>{console.log(chalk.magenta("Streaming has been stopped. Thank you for using our service.")),ffmpegProcess&&ffmpegProcess.kill("SIGINT"),process.exit()}))},reStreamShopee=async({videoUrl:e,rtmpServer:t=null,rtmpKey:o=null,isInfiniteMode:r=!1,streamDuration:a=0})=>new Promise((async(n,s)=>{try{let n=null,s=`${__dirname}/../${e}`,i="stream";if(!e.includes("mp4")&&!e.includes("flv")){if(n=await getShopeeStreamDetails(e),!n)throw new Error("Stream details could not be retrieved.");s=decodeURIComponent(n.play_url),i="restream"}const l=`${__dirname}/../stream_output/${n?.room_id}-${n?.username}`;await processVideo({liveUrl:s,rtmpServer:t,rtmpKey:o,isInfiniteMode:r,streamDuration:a,baseFilePath:l,mode:i})}catch(e){s(e),console.error("Error in reStreamShopee function: ",e)}})),downloadStream=async({videoUrl:e,durasiVideo:t=0,rtmpServer:o=null,rtmpKey:r=null,isInfinite:a=!1})=>{try{const n=getStreamProvider(e);let s=null;switch(n){case"shopee":case"filestream":s=await reStreamShopee({videoUrl:e,streamDuration:t?60*t:null,rtmpServer:o,rtmpKey:r,isInfiniteMode:a});break;case"tiktok":s=await tiktokDownload({videoUrl:e,duration:t?60*parseInt(t):null,rtmpServer:o,rtmpKey:r,isInfiniteMode:a});break;default:throw Error(`Platform "${n}" Not Supported Yet!`)}return s}catch(e){throw Error(e)}},getStreamProvider=e=>{let t="";return t=e.includes("http")?new URL(e).hostname:"filestream",t.includes("tiktok")?"tiktok":t.includes("youtube")?"youtube":t.includes("twitch")?"twitch":t.includes("facebook")?"facebook":t.includes("tokopedia")?"tokopedia":t.includes("shopee")?"shopee":t.includes("file")?"filestream":t},getShopeeStreamDetails=async e=>{const t=new URL(e),o=t.hostname,r=t.searchParams.get("session");return fetch(`https://${o}/api/v1/session/${r}`,{headers:{Host:`${o}`,"Sec-Ch-Ua":'"Brave";v="119", "Chromium";v="119", "Not?A_Brand";v="24"',"Sec-Ch-Ua-Mobile":"?0","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","X-Api-Source":"pc","Content-Type":"application/json",Accept:"application/json","X-Shopee-Language":"id","X-Requested-With":"XMLHttpRequest","Sec-Ch-Ua-Platform":'"macOS"',"Sec-Gpc":"1","Accept-Language":"id-ID,id;q=0.6","Sec-Fetch-Site":"same-origin","Sec-Fetch-Mode":"cors","Sec-Fetch-Dest":"empty",Referer:`https://${o}/?is_from_login=true&is_from_login=true`,"Accept-Encoding":"gzip, deflate, br"}}).then((async e=>{const t=await e.json();return 0==t.err_code?t?.data?.session:t}))},tiktokStreamData=async e=>{const t=`https://www.tiktok.com/@${e}/live`,o=(await fetch(t,{headers:{"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"}}).then((e=>e.text()))).match(/room_id=(\d+)/);if(!o)throw new Error("No live stream found");const r=o[1];console.info(`\nFound live stream with room id ${r}!`);const a=`https://www.tiktok.com/api/live/detail/?aid=1988&roomID=${r}`,{LiveRoomInfo:n}=await fetch(a).then((e=>e.json())),{title:s,liveUrl:i}=n;return{title:s,liveUrl:i}},tiktokDownload=async({videoUrl:e,outputDirectory:t="stream_output",format:o="mp4",duration:r=0,rtmpKey:a=null,rtmpServer:n=null,isInfiniteMode:s=!1})=>new Promise((async(i,l)=>{try{const i=e.split("/"),l=i[i.length-2].replace("@",""),{title:c,liveUrl:d}=await tiktokStreamData(l),p=t.endsWith(o)?t:`${t.replace(/\/$/,"")}/${l}-${Date.now()}.${o}`;mkdirSync(path.dirname(p),{recursive:!0}),await processVideo({liveUrl:d,rtmpServer:n,rtmpKey:a,isInfiniteMode:s,streamDuration:r,baseFilePath:p,mode:"restream"}),console.info("\nCtrl+C to stop downloading and exit")}catch(e){l(e)}}));module.exports={ffmpegProcess:ffmpegProcess,reStreamShopee:reStreamShopee,getShopeeStreamDetails:getShopeeStreamDetails,downloadStream:downloadStream,decodeUnicode:decodeUnicode,tiktokDownload:tiktokDownload};

0 commit comments

Comments
 (0)