|
1 | 1 | import { PassThrough } from 'node:stream' |
2 | 2 | import { encodeTrack, http1makeRequest, logger } from '../utils.js' |
| 3 | +import HLSHandler from '../playback/hls/HLSHandler.js' |
3 | 4 |
|
4 | 5 | const AUTH = 'AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA' |
5 | 6 |
|
@@ -207,37 +208,53 @@ export default class TwitterSource { |
207 | 208 |
|
208 | 209 | async loadStream(decodedTrack, url) { |
209 | 210 | try { |
210 | | - const options = { |
211 | | - method: 'GET', |
212 | | - streamOnly: true, |
213 | | - headers: { |
214 | | - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', |
215 | | - 'Referer': 'https://twitter.com/' |
216 | | - } |
| 211 | + const headers = { |
| 212 | + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', |
| 213 | + 'Referer': 'https://twitter.com/' |
217 | 214 | } |
218 | 215 |
|
219 | | - const response = await http1makeRequest(url, options) |
| 216 | + if (url.includes('.m3u8')) { |
| 217 | + const stream = new HLSHandler(url, { |
| 218 | + type: 'fmp4', |
| 219 | + strategy: 'segmented', |
| 220 | + headers, |
| 221 | + localAddress: this.nodelink.routePlanner?.getIP() |
| 222 | + }) |
| 223 | + return { stream, type: 'fmp4' } |
| 224 | + } |
| 225 | + |
| 226 | + const response = await http1makeRequest(url, { |
| 227 | + method: 'GET', |
| 228 | + headers, |
| 229 | + streamOnly: true |
| 230 | + }) |
| 231 | + |
220 | 232 | if (response.error || !response.stream) throw response.error || new Error('Failed to get stream') |
221 | 233 |
|
222 | 234 | const stream = new PassThrough() |
| 235 | + let finished = false |
| 236 | + const finish = () => { |
| 237 | + if (finished) return |
| 238 | + finished = true |
| 239 | + if (!stream.writableEnded) { |
| 240 | + stream.emit('finishBuffering') |
| 241 | + stream.end() |
| 242 | + } |
| 243 | + } |
223 | 244 |
|
224 | 245 | response.stream.on('data', (chunk) => { |
225 | 246 | if (!stream.destroyed) stream.write(chunk) |
226 | 247 | }) |
227 | 248 |
|
228 | | - response.stream.on('end', () => { |
229 | | - if (!stream.destroyed) { |
230 | | - stream.emit('finishBuffering') |
231 | | - stream.end() |
232 | | - } |
233 | | - }) |
| 249 | + response.stream.on('end', finish) |
| 250 | + response.stream.on('close', finish) |
234 | 251 |
|
235 | 252 | response.stream.on('error', (err) => { |
236 | 253 | logger('error', 'Twitter', `External stream error: ${err.message}`) |
237 | 254 | if (!stream.destroyed) stream.destroy(err) |
238 | 255 | }) |
239 | 256 |
|
240 | | - return { stream, type: decodedTrack.pluginInfo?.isHLS ? 'application/x-mpegURL' : 'video/mp4' } |
| 257 | + return { stream, type: 'video/mp4' } |
241 | 258 | } catch (e) { |
242 | 259 | logger('error', 'Twitter', `Failed to load stream: ${e.message}`) |
243 | 260 | return { exception: { message: e.message, severity: 'fault' } } |
|
0 commit comments