| | import crc32 from './crc32.js' |
| | import http from 'axios' |
| | import express from 'express' |
| |
|
| | const app = express() |
| | const port = 7860 |
| |
|
| | app.use(express.json()) |
| | app.use(express.urlencoded({ extended: true })) |
| |
|
| | const upload_buffer = async data => { |
| | try { |
| | const file = Buffer.from(data) |
| | const hash = crc32(file) |
| | const upload_info = await http({ |
| | method: 'GET', |
| | url: 'https://api.xs.cx/upload/sg' |
| | }) |
| | const upload_result = await http({ |
| | method: 'POST', |
| | url: upload_info.data.url, |
| | headers: { |
| | 'content-crc32': hash, |
| | 'authorization': upload_info.data.authorization |
| | }, |
| | data: file |
| | }) |
| | if (upload_result.status == 200) { |
| | return { |
| | vid: upload_info.data.vid, |
| | url: `https://sf16-sg-default.akamaized.net/obj/${upload_info.data.uri}` |
| | } |
| | } else { |
| | throw Error |
| | } |
| | } catch (e) { |
| | console.log(e.toString()) |
| | } |
| | } |
| |
|
| | const upload_file = async url => { |
| | try { |
| | const file_url = url |
| | const file = await http({ |
| | method: 'GET', |
| | url: file_url, |
| | responseType: 'arraybuffer' |
| | }) |
| | const hash = crc32(file.data) |
| | const upload_info = await http({ |
| | method: 'GET', |
| | url: 'https://api.xs.cx/upload/sg' |
| | }) |
| | const upload_result = await http({ |
| | method: 'POST', |
| | url: upload_info.data.url, |
| | headers: { |
| | 'content-crc32': hash, |
| | 'authorization': upload_info.data.authorization |
| | }, |
| | data: file.data |
| | }) |
| | if (upload_result.status == 200) { |
| | return { |
| | vid: upload_info.data.vid, |
| | url: `https://sf16-sg-default.akamaized.net/obj/${upload_info.data.uri}` |
| | } |
| | } else { |
| | throw Error |
| | } |
| | } catch (e) { |
| | console.log(e.toString()) |
| | } |
| | } |
| |
|
| | const m3u8_parse = async url => { |
| | let lock = false |
| | while (!lock) { |
| | try { |
| | const m3u8_file = await http({ |
| | method: 'GET', |
| | url: url |
| | }) |
| | if (m3u8_file.status != 200) { |
| | console.log(`[m3u8加载失败] ${url}`) |
| | return |
| | } |
| | let text = m3u8_file.data |
| | const is_m3u8 = m3u8_file.data.match(/\n.*?\.m3u8(\n|$)/gim)?.at(0) |
| | if (is_m3u8) { |
| | let new_url |
| | if (/^\nhttp/i.test(url)) { |
| | new_url = is_m3u8.replace('\n', '') |
| | } else { |
| | new_url = url.replace(url.split('/').pop(), is_m3u8.replace('\n', '')) |
| | } |
| | text = m3u8_parse(new_url) |
| | } else if (text.startsWith('#')) { |
| | const queue = text.match(/\n.*.(ts|png|jpg|jpeg|gif|webp)/gim) |
| | while (queue.length) { |
| | await Promise.all(queue.splice(0, 50).map(async item => { |
| | let ts_url |
| | if (/^\nhttp/i.test(item)) { |
| | ts_url = item.replace('\n', '') |
| | } else { |
| | ts_url = url.replace(url.split('/').pop(), item.replace('\n', '')) |
| | } |
| | |
| | |
| | |
| | |
| | let count = 1 |
| | let upload_result |
| | while (!upload_result) { |
| | try { |
| | const result = await upload_file(ts_url) |
| | if (/^http/i.test(result.url)) { |
| | upload_result = result.url |
| | |
| | |
| | |
| | |
| | } else { |
| | console.log(`[上传失败] ${url}`) |
| | } |
| | } catch (e) { |
| | count += 1 |
| | if (count == 10) upload_result = 'ERROR_' |
| | console.log(e, ts_url) |
| | } |
| | } |
| | if (upload_result == 'ERROR_') { |
| | lock = false |
| | throw Error |
| | } |
| | text = text.replace(item, `\n${upload_result}`); |
| | })) |
| | } |
| | } |
| | return text |
| | } catch (e) { |
| | console.log(e) |
| | } |
| | } |
| | } |
| |
|
| | app.get('*', async (req, res) => { |
| | try { |
| | if (!/\/http/i.test(req.path)) throw Error |
| | const file = await m3u8_parse(req.path.replace(/^\//, '')) |
| | if (!file.startsWith('#')) throw Error |
| | res.send(await upload_buffer(file)) |
| | } catch (e) { |
| | res.send(e.toString()) |
| | } |
| | }) |
| |
|
| | app.listen(port, async () => { |
| | console.log(`http://localhost:${port}`) |
| | }) |