|
import HLSParser from "hls-parser"; |
|
import { env } from "../../config.js"; |
|
|
|
let _token; |
|
|
|
function getExp(token) { |
|
return JSON.parse( |
|
Buffer.from(token.split('.')[1], 'base64') |
|
).exp * 1000; |
|
} |
|
|
|
const getToken = async () => { |
|
if (_token && getExp(_token) > new Date().getTime()) { |
|
return _token; |
|
} |
|
|
|
const req = await fetch('https://graphql.api.dailymotion.com/oauth/token', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', |
|
'User-Agent': 'dailymotion/240213162706 CFNetwork/1492.0.1 Darwin/23.3.0', |
|
'Authorization': 'Basic MGQyZDgyNjQwOWFmOWU3MmRiNWQ6ODcxNmJmYTVjYmEwMmUwMGJkYTVmYTg1NTliNDIwMzQ3NzIyYWMzYQ==' |
|
}, |
|
body: 'traffic_segment=&grant_type=client_credentials' |
|
}).then(r => r.json()).catch(() => {}); |
|
|
|
if (req.access_token) { |
|
return _token = req.access_token; |
|
} |
|
} |
|
|
|
export default async function({ id }) { |
|
const token = await getToken(); |
|
if (!token) return { error: "fetch.fail" }; |
|
|
|
const req = await fetch('https://graphql.api.dailymotion.com/', |
|
{ |
|
method: 'POST', |
|
headers: { |
|
'User-Agent': 'dailymotion/240213162706 CFNetwork/1492.0.1 Darwin/23.3.0', |
|
Authorization: `Bearer ${token}`, |
|
'Content-Type': 'application/json', |
|
'X-DM-AppInfo-Version': '7.16.0_240213162706', |
|
'X-DM-AppInfo-Type': 'iosapp', |
|
'X-DM-AppInfo-Id': 'com.dailymotion.dailymotion' |
|
}, |
|
body: JSON.stringify({ |
|
operationName: "Media", |
|
query: ` |
|
query Media($xid: String!, $password: String) { |
|
media(xid: $xid, password: $password) { |
|
__typename |
|
... on Video { |
|
xid |
|
hlsURL |
|
duration |
|
title |
|
channel { |
|
displayName |
|
} |
|
} |
|
} |
|
} |
|
`, |
|
variables: { xid: id } |
|
}) |
|
} |
|
).then(r => r.status === 200 && r.json()).catch(() => {}); |
|
|
|
const media = req?.data?.media; |
|
|
|
if (media?.__typename !== 'Video' || !media.hlsURL) { |
|
return { error: "fetch.empty" } |
|
} |
|
|
|
if (media.duration > env.durationLimit) { |
|
return { error: "content.too_long" }; |
|
} |
|
|
|
const manifest = await fetch(media.hlsURL).then(r => r.text()).catch(() => {}); |
|
if (!manifest) return { error: "fetch.fail" }; |
|
|
|
const bestQuality = HLSParser.parse(manifest).variants |
|
.filter(v => v.codecs.includes('avc1')) |
|
.reduce((a, b) => a.bandwidth > b.bandwidth ? a : b); |
|
if (!bestQuality) return { error: "fetch.empty" } |
|
|
|
const fileMetadata = { |
|
title: media.title, |
|
artist: media.channel.displayName |
|
} |
|
|
|
return { |
|
urls: bestQuality.uri, |
|
isHLS: true, |
|
filenameAttributes: { |
|
service: 'dailymotion', |
|
id: media.xid, |
|
title: fileMetadata.title, |
|
author: fileMetadata.artist, |
|
resolution: `${bestQuality.resolution.width}x${bestQuality.resolution.height}`, |
|
qualityLabel: `${bestQuality.resolution.height}p`, |
|
extension: 'mp4' |
|
}, |
|
fileMetadata |
|
} |
|
} |