Incude vkvideo extractor #445

Closed
opened 2025-10-18 20:26:05 +00:00 by GLlgGL · 12 comments
GLlgGL commented 2025-10-18 20:26:05 +00:00 (Migrated from github.com)
Hi There is a vkvideo extractor here https://github.com/Gujal00/ResolveURL/blob/master/script.module.resolveurl/lib/resolveurl/plugins/vk.py Can you add? This website main server source is vkvideo [Movie](https://www.filmaon.bz/filma/our-fault/) The link is like this https://vkvideo.ru/video_ext.php?oid=319533096&id=456239326&hash=c25be5174fb15ba2
GLlgGL commented 2025-11-01 10:00:43 +00:00 (Migrated from github.com)

I asked the author and his extractor is working well on that link

I failed to convert it to typescript

image

I asked the author and his extractor is working well on that link I failed to convert it to typescript ![image](https://github.com/user-attachments/assets/01bc75d2-fd84-4b74-a6c6-34f56f3941a8)
GLlgGL commented 2025-11-04 16:24:39 +00:00 (Migrated from github.com)

I tried to convert but I get

"You were rate-limited" error

import { Context, Meta, UrlResult, Format } from '../types';
import { Extractor } from './Extractor';
import { guessHeightFromPlaylist } from '../utils/height';

import { NotFoundError } from '../error';

export class VKResolver extends Extractor {
public readonly id = 'vk';
public readonly label = 'VK';
public override readonly ttl = 10800000; // 3 hours
private domains = ['vk.com', 'vkvideo.ru'];

public supports(_ctx: Context, url: URL): boolean {
//// _ctx is deliberately kept to satisfy the signature
return this.domains.includes(url.host);
}

protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
const query = new URLSearchParams(url.search);
const oid = query.get('oid');
const videoId = query.get('id');
// const hash = query.get('hash'); // unused, removed
const videoList = query.get('list') ?? '';

if (!oid || !videoId) {
  throw new NotFoundError('Missing oid or video id in URL');
}

const headers: Record<string, string> = {
  'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36',
  Referer: `https://${url.host}/`,
  Origin: `https://${url.host}`,
  'X-Requested-With': 'XMLHttpRequest',
};

const postData = new URLSearchParams();

postData.set('act', 'show');
postData.set('al', '1');
postData.set('video', ${oid}_${videoId});
if (videoList) {
postData.set('list', videoList);
postData.set('load_playlist', '1');
postData.set('module', 'direct');
postData.set('show_next', '1');
postData.set('playlist_id', ${oid}_-2);
}

const html = await this.fetcher.textPost(ctx, new URL(`https://${url.host}/al_video.php?act=show`), postData.toString(), { headers });

let jsonData: any;
try {
  const trimmed = html.startsWith('<!--') ? html.slice(4) : html;
  jsonData = JSON.parse(trimmed);
} catch {
  throw new NotFoundError('Failed to parse VK response');
}

// Extract playlist sources
let payload: any[] = [];
let playerParams: Record<string, string> = {};

for (const item of jsonData.payload) {
  if (Array.isArray(item)) payload = item;
}

for (const item of payload) {
  if (typeof item === 'object' && item.player?.params?.[0]) {
    playerParams = item.player.params[0];
  }
}

const sources: UrlResult[] = [];

for (const key of Object.keys(playerParams)) {
  if (key.startsWith('url')) {
    const videoUrl = playerParams[key];
    if (videoUrl) {
      const height = await guessHeightFromPlaylist(ctx, this.fetcher, new URL(videoUrl), url, { headers: { Referer: url.href } });
      sources.push({
        url: new URL(videoUrl),
        format: Format.hls,
        label: this.label,
        sourceId: `${this.id}_${meta.countryCodes?.join('_') ?? 'unknown'}`,
        ttl: this.ttl,
        meta: { ...meta, height },
        requestHeaders: { Referer: `https://${url.host}/` },
      });
    }
  }
}

if (!sources.length) {
  throw new NotFoundError('No video sources found for VK URL');
}

return sources;

}
}

I tried to convert but I get "You were rate-limited" error import { Context, Meta, UrlResult, Format } from '../types'; import { Extractor } from './Extractor'; import { guessHeightFromPlaylist } from '../utils/height'; import { NotFoundError } from '../error'; export class VKResolver extends Extractor { public readonly id = 'vk'; public readonly label = 'VK'; public override readonly ttl = 10800000; // 3 hours private domains = ['vk.com', 'vkvideo.ru']; public supports(_ctx: Context, url: URL): boolean { //// _ctx is deliberately kept to satisfy the signature return this.domains.includes(url.host); } protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> { const query = new URLSearchParams(url.search); const oid = query.get('oid'); const videoId = query.get('id'); // const hash = query.get('hash'); // unused, removed const videoList = query.get('list') ?? ''; if (!oid || !videoId) { throw new NotFoundError('Missing oid or video id in URL'); } const headers: Record<string, string> = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36', Referer: `https://${url.host}/`, Origin: `https://${url.host}`, 'X-Requested-With': 'XMLHttpRequest', }; const postData = new URLSearchParams(); postData.set('act', 'show'); postData.set('al', '1'); postData.set('video', `${oid}_${videoId}`); if (videoList) { postData.set('list', videoList); postData.set('load_playlist', '1'); postData.set('module', 'direct'); postData.set('show_next', '1'); postData.set('playlist_id', `${oid}_-2`); } const html = await this.fetcher.textPost(ctx, new URL(`https://${url.host}/al_video.php?act=show`), postData.toString(), { headers }); let jsonData: any; try { const trimmed = html.startsWith('<!--') ? html.slice(4) : html; jsonData = JSON.parse(trimmed); } catch { throw new NotFoundError('Failed to parse VK response'); } // Extract playlist sources let payload: any[] = []; let playerParams: Record<string, string> = {}; for (const item of jsonData.payload) { if (Array.isArray(item)) payload = item; } for (const item of payload) { if (typeof item === 'object' && item.player?.params?.[0]) { playerParams = item.player.params[0]; } } const sources: UrlResult[] = []; for (const key of Object.keys(playerParams)) { if (key.startsWith('url')) { const videoUrl = playerParams[key]; if (videoUrl) { const height = await guessHeightFromPlaylist(ctx, this.fetcher, new URL(videoUrl), url, { headers: { Referer: url.href } }); sources.push({ url: new URL(videoUrl), format: Format.hls, label: this.label, sourceId: `${this.id}_${meta.countryCodes?.join('_') ?? 'unknown'}`, ttl: this.ttl, meta: { ...meta, height }, requestHeaders: { Referer: `https://${url.host}/` }, }); } } } if (!sources.length) { throw new NotFoundError('No video sources found for VK URL'); } return sources; } }
GLlgGL commented 2025-12-01 09:31:34 +00:00 (Migrated from github.com)

I get this error on the post

Got 429 (Too Many Requests) for https://vkvideo.ru/al_video.php?act=show

I get this error on the post `Got 429 (Too Many Requests) for https://vkvideo.ru/al_video.php?act=show`
GLlgGL commented 2025-12-03 17:05:09 +00:00 (Migrated from github.com)

Ok so I've advanced with this and the mediaflow proxy is needed.

The problem is that the mediaflow proxy needs some edits to be able to hande this provider...

Master is like this

https://vkvd591.okcdn.ru/?srcIp=185.187.0.130&pr=40&expires=1765235190685&srcAg=CHROME&fromCache=1&ch=1336333768&ms=185.226.53.179&type=1&sig=_2cGGKog4c8&ct=6&urls=185.226.55.233&clientType=13&appId=512000384397&zs=43&id=9464193092136

Is has inside

#EXTM3U #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1136890,AVERAGE-BANDWIDTH=531299,QUALITY=sd,FRAME-RATE=24,RESOLUTION=852x354 /expires/1765236727874/srcIp/185.187.0.130/pr/40/srcAg/CHROME/ch/1676822812/ms/185.226.53.179/mid/10754960730152/type/2/sig/ZhcTk-IMrqM/ct/8/urls/185.226.52.167/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=485431,AVERAGE-BANDWIDTH=266838,QUALITY=lowest,FRAME-RATE=24,RESOLUTION=426x178 /expires/1765236727874/srcIp/185.187.0.130/pr/40/srcAg/CHROME/ch/1676822812/ms/185.226.53.179/mid/10754960730152/type/0/sig/Jj4sQQ5oFBQ/ct/8/urls/185.226.52.167/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=836641,AVERAGE-BANDWIDTH=393641,QUALITY=low,FRAME-RATE=24,RESOLUTION=640x266 /expires/1765236727874/srcIp/185.187.0.130/pr/40/srcAg/CHROME/ch/1676822812/ms/185.226.53.179/mid/10754960730152/type/1/sig/gWhVpAhPxyY/ct/8/urls/185.226.52.167/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2275783,AVERAGE-BANDWIDTH=983384,QUALITY=hd,FRAME-RATE=24,RESOLUTION=1280x532 /expires/1765236727874/srcIp/185.187.0.130/pr/40/srcAg/CHROME/ch/1676822812/ms/185.226.53.179/mid/10754960730152/type/3/sig/GX4o1yHSKgg/ct/8/urls/185.226.52.167/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=337936,AVERAGE-BANDWIDTH=201553,QUALITY=mobile,FRAME-RATE=24,RESOLUTION=256x106 /expires/1765236727874/srcIp/185.187.0.130/pr/40/srcAg/CHROME/ch/1676822812/ms/185.226.53.179/mid/10754960730152/type/4/sig/o5cX1H6wE4k/ct/8/urls/185.226.52.167/clientType/13/zs/43/id/9464193092136/video/

In reality segments become

https://vkvd591.okcdn.ru/?expires=...&bytes=0-12987

So its a mix between hls and mpd mp4 with segments which are added with byte ranges

The mediaflow needs rewrite un support it natively but this takes time to do it and for the moment I will leave it as to much hasle + at the end might be playable only on same IP as the requestor like vidguard.

Ok so I've advanced with this and the mediaflow proxy is needed. The problem is that the mediaflow proxy needs some edits to be able to hande this provider... Master is like this `https://vkvd591.okcdn.ru/?srcIp=185.187.0.130&pr=40&expires=1765235190685&srcAg=CHROME&fromCache=1&ch=1336333768&ms=185.226.53.179&type=1&sig=_2cGGKog4c8&ct=6&urls=185.226.55.233&clientType=13&appId=512000384397&zs=43&id=9464193092136` Is has inside `#EXTM3U #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1136890,AVERAGE-BANDWIDTH=531299,QUALITY=sd,FRAME-RATE=24,RESOLUTION=852x354 /expires/1765236727874/srcIp/185.187.0.130/pr/40/srcAg/CHROME/ch/1676822812/ms/185.226.53.179/mid/10754960730152/type/2/sig/ZhcTk-IMrqM/ct/8/urls/185.226.52.167/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=485431,AVERAGE-BANDWIDTH=266838,QUALITY=lowest,FRAME-RATE=24,RESOLUTION=426x178 /expires/1765236727874/srcIp/185.187.0.130/pr/40/srcAg/CHROME/ch/1676822812/ms/185.226.53.179/mid/10754960730152/type/0/sig/Jj4sQQ5oFBQ/ct/8/urls/185.226.52.167/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=836641,AVERAGE-BANDWIDTH=393641,QUALITY=low,FRAME-RATE=24,RESOLUTION=640x266 /expires/1765236727874/srcIp/185.187.0.130/pr/40/srcAg/CHROME/ch/1676822812/ms/185.226.53.179/mid/10754960730152/type/1/sig/gWhVpAhPxyY/ct/8/urls/185.226.52.167/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2275783,AVERAGE-BANDWIDTH=983384,QUALITY=hd,FRAME-RATE=24,RESOLUTION=1280x532 /expires/1765236727874/srcIp/185.187.0.130/pr/40/srcAg/CHROME/ch/1676822812/ms/185.226.53.179/mid/10754960730152/type/3/sig/GX4o1yHSKgg/ct/8/urls/185.226.52.167/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=337936,AVERAGE-BANDWIDTH=201553,QUALITY=mobile,FRAME-RATE=24,RESOLUTION=256x106 /expires/1765236727874/srcIp/185.187.0.130/pr/40/srcAg/CHROME/ch/1676822812/ms/185.226.53.179/mid/10754960730152/type/4/sig/o5cX1H6wE4k/ct/8/urls/185.226.52.167/clientType/13/zs/43/id/9464193092136/video/` In reality segments become `https://vkvd591.okcdn.ru/?expires=...&bytes=0-12987` So its a mix between hls and mpd mp4 with segments which are added with byte ranges The mediaflow needs rewrite un support it natively but this takes time to do it and for the moment I will leave it as to much hasle + at the end might be playable only on same IP as the requestor like vidguard.
GLlgGL commented 2025-12-03 20:37:34 +00:00 (Migrated from github.com)

Lets keep it open to not forgot it.

Lets keep it open to not forgot it.
GLlgGL commented 2025-12-04 15:07:24 +00:00 (Migrated from github.com)

I'm really close with this but I don't know why the mediaflow gets the full mp4 file which stremio fails to play and gets timeout
For ex full mp4 file
https://vk6-9.vkuser.net/?srcIp=xxxxxxxxx&pr=40&expires=1765315293688&srcAg=CHROME&fromCache=1&ch=1336333768&ms=95.142.206.168&type=1&sig=LQf4pduodWU&ct=6&urls=45.136.22.202%3B185.226.52.166&clientType=13&appId=512000384397&zs=43&id=9576010484237

Instead should get ranges
Segment ranges
https://vk6-9.vkuser.net/?expires=1765314411759&srcIp=xxxxxx&pr=40&srcAg=CHROME&ms=xxxxxxxx&type=2&sig=Fct7_gaCQNc&ct=11&urls=45.136.22.202%3B185.226.52.166&clientType=13&zs=43&id=9576010484237&bytes=0-11811

I'm really close with this but I don't know why the mediaflow gets the full mp4 file which stremio fails to play and gets timeout For ex full mp4 file `https://vk6-9.vkuser.net/?srcIp=xxxxxxxxx&pr=40&expires=1765315293688&srcAg=CHROME&fromCache=1&ch=1336333768&ms=95.142.206.168&type=1&sig=LQf4pduodWU&ct=6&urls=45.136.22.202%3B185.226.52.166&clientType=13&appId=512000384397&zs=43&id=9576010484237` Instead should get ranges Segment ranges `https://vk6-9.vkuser.net/?expires=1765314411759&srcIp=xxxxxx&pr=40&srcAg=CHROME&ms=xxxxxxxx&type=2&sig=Fct7_gaCQNc&ct=11&urls=45.136.22.202%3B185.226.52.166&clientType=13&zs=43&id=9576010484237&bytes=0-11811`
GLlgGL commented 2025-12-10 08:22:57 +00:00 (Migrated from github.com)

We should also make this work as now I see that this provider offers videos till 4K.

On my last attempt I had difficultes because the provider hosts MPD and MP4 but I failed to make it work through mediaflow...

We should also make this work as now I see that this provider offers videos till 4K. On my last attempt I had difficultes because the provider hosts MPD and MP4 but I failed to make it work through mediaflow...
GLlgGL commented 2025-12-10 13:21:05 +00:00 (Migrated from github.com)

Hey I need your help here

I have this code which now doesnt give rate limit...I get a result(best quality) but is not playable
I can't check what is the final url that being returned because is not showing in the logs

Using curl the link returned is something like this and it work on vlc. Does stremio can play this? And what might be wrong? The links work everywhere so are not ip locked

Master
https://vkvd289.okcdn.ru/video.m3u8?cmd=videoPlayerCdn&expires=1765623902829&srcIp=xxxxxxxxx&pr=40&srcAg=UNKNOWN&ch=1676822812&ms=185.226.52.167&mid=10754960730152&type=2&sig=aCqDNSyEkHE&ct=8&urls=185.226.53.179&clientType=13&zs=43&id=9464193092136&m3u8

Inside
#EXTM3U #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1136890,AVERAGE-BANDWIDTH=531299,QUALITY=sd,FRAME-RATE=24,RESOLUTION=852x354 /expires/1765623902829/srcIp/xxxxxxxx/pr/40/srcAg/UNKNOWN/ch/1676822812/ms/185.226.52.167/mid/10754960730152/type/2/sig/aCqDNSyEkHE/ct/8/urls/185.226.53.179/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=485431,AVERAGE-BANDWIDTH=266838,QUALITY=lowest,FRAME-RATE=24,RESOLUTION=426x178 /expires/1765623902829/srcIp/xxxxxxxxx/pr/40/srcAg/UNKNOWN/ch/1676822812/ms/185.226.52.167/mid/10754960730152/type/0/sig/xrMD4tbFTz8/ct/8/urls/185.226.53.179/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=836641,AVERAGE-BANDWIDTH=393641,QUALITY=low,FRAME-RATE=24,RESOLUTION=640x266 /expires/1765623902829/srcIp/xxxxxxxx/pr/40/srcAg/UNKNOWN/ch/1676822812/ms/185.226.52.167/mid/10754960730152/type/1/sig/a6mMfqkJ7ZY/ct/8/urls/185.226.53.179/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2275783,AVERAGE-BANDWIDTH=983384,QUALITY=hd,FRAME-RATE=24,RESOLUTION=1280x532 /expires/1765623902829/srcIp/xxxxxxxc/pr/40/srcAg/UNKNOWN/ch/1676822812/ms/185.226.52.167/mid/10754960730152/type/3/sig/T8N9bXspsWc/ct/8/urls/185.226.53.179/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=337936,AVERAGE-BANDWIDTH=201553,QUALITY=mobile,FRAME-RATE=24,RESOLUTION=256x106 /expires/1765623902829/srcIp/xxxxxxx/pr/40/srcAg/UNKNOWN/ch/1676822812/ms/185.226.52.167/mid/10754960730152/type/4/sig/emQkM4xuDpg/ct/8/urls/185.226.53.179/clientType/13/zs/43/id/9464193092136/video/

`import { Context, Meta, UrlResult, Format } from '../types';
import { Extractor } from './Extractor';
import { guessHeightFromPlaylist } from '../utils/height';
import { NotFoundError } from '../error';

export class VKResolver extends Extractor {
public readonly id = 'vk';
public readonly label = 'VK';
public override readonly ttl = 10800000; // 3 hours

private domains = ['vk.com', 'vkvideo.ru'];

public supports(_: Context, url: URL): boolean {
return this.domains.includes(url.host);
}

protected async extractInternal(
ctx: Context,
url: URL,
meta: Meta
): Promise<UrlResult[]> {

// --- extract query ---
const query = new URLSearchParams(url.search);
const oid = query.get('oid');
const videoId = query.get('id');
const videoList = query.get('list');

if (!oid || !videoId) {
  throw new NotFoundError('Missing VK oid or video id');
}

// --- headers (needed only for al_video.php) ---
const headers: Record<string, string> = {
  'User-Agent':
    'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36',
  Referer: `https://${url.host}/`,
  Origin: `https://${url.host}`,
  'X-Requested-With': 'XMLHttpRequest',
};

// --- POST body ---
const postData = new URLSearchParams({
  act: 'show',
  al: '1',
  video: `${oid}_${videoId}`,
});

if (videoList) {
  postData.set('list', videoList);
  postData.set('load_playlist', '1');
  postData.set('module', 'direct');
  postData.set('show_next', '1');
  postData.set('playlist_id', `${oid}_-2`);
}

// --- request ---
const response = await this.fetcher.textPost(
  ctx,
  new URL(`https://${url.host}/al_video.php`),
  postData.toString(),
  { headers }
);

// --- parse JSON ---
let json: any;
try {
  json = JSON.parse(response.replace(/^<!--/, ''));
} catch {
  throw new NotFoundError('VK response not JSON');
}

// --- locate payload ---
const payload = Array.isArray(json.payload?.[1])
  ? json.payload[1]
  : [];

const params =
  payload.find((p: any) => p?.player?.params)?.player?.params?.[0];

if (!params || typeof params !== 'object') {
  throw new NotFoundError('VK player params missing');
}

// --- extract URLs ---
const results: UrlResult[] = [];

for (const [key, value] of Object.entries(params)) {
  if (!key.startsWith('url') || typeof value !== 'string') continue;

  let height: number | undefined;

  // key-based height (url720 → 720)
  const parsed = parseInt(key.replace('url', ''), 10);
  if (!Number.isNaN(parsed)) {
    height = parsed;
  } else {
  
    try {
      height = await guessHeightFromPlaylist(
        ctx,
        this.fetcher,
        new URL(value),
        url,
        { headers }
      );
    } catch {
      height = undefined;
    }
  }

results.push({

url: new URL(value + '.m3u8'),
format: Format.hls,
label: VK ${height ?? 'auto'}p,
sourceId: this.id,
ttl: this.ttl,
meta: { ...meta, height },
requestHeaders: {
Referer: https://${url.host}/,
},
});

}

if (!results.length) {
  throw new NotFoundError('No VK streams found');
}


results.sort(
  (a, b) => (b.meta?.height ?? 0) - (a.meta?.height ?? 0)
);


return [results[0]!];

}
}
`

You can run it yourself

curl 'https://vkvideo.ru/al_video.php?act=show'
-X POST
-H 'User-Agent: Mozilla/5.0'
-H 'Referer: https://vkvideo.ru/'
-H 'Origin: https://vkvideo.ru'
-H 'X-Requested-With: XMLHttpRequest'
--data 'act=show&al=1&video=319533096_456239475' \ > response.json

Than

iconv -f utf-8 -t utf-8 response.json | sed 's/\\u0000//g'

Hey I need your help here I have this code which now doesnt give rate limit...I get a result(best quality) but is not playable I can't check what is the final url that being returned because is not showing in the logs Using curl the link returned is something like this and it work on vlc. Does stremio can play this? And what might be wrong? The links work everywhere so are not ip locked Master `https://vkvd289.okcdn.ru/video.m3u8?cmd=videoPlayerCdn&expires=1765623902829&srcIp=xxxxxxxxx&pr=40&srcAg=UNKNOWN&ch=1676822812&ms=185.226.52.167&mid=10754960730152&type=2&sig=aCqDNSyEkHE&ct=8&urls=185.226.53.179&clientType=13&zs=43&id=9464193092136&m3u8` Inside `#EXTM3U #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1136890,AVERAGE-BANDWIDTH=531299,QUALITY=sd,FRAME-RATE=24,RESOLUTION=852x354 /expires/1765623902829/srcIp/xxxxxxxx/pr/40/srcAg/UNKNOWN/ch/1676822812/ms/185.226.52.167/mid/10754960730152/type/2/sig/aCqDNSyEkHE/ct/8/urls/185.226.53.179/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=485431,AVERAGE-BANDWIDTH=266838,QUALITY=lowest,FRAME-RATE=24,RESOLUTION=426x178 /expires/1765623902829/srcIp/xxxxxxxxx/pr/40/srcAg/UNKNOWN/ch/1676822812/ms/185.226.52.167/mid/10754960730152/type/0/sig/xrMD4tbFTz8/ct/8/urls/185.226.53.179/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=836641,AVERAGE-BANDWIDTH=393641,QUALITY=low,FRAME-RATE=24,RESOLUTION=640x266 /expires/1765623902829/srcIp/xxxxxxxx/pr/40/srcAg/UNKNOWN/ch/1676822812/ms/185.226.52.167/mid/10754960730152/type/1/sig/a6mMfqkJ7ZY/ct/8/urls/185.226.53.179/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2275783,AVERAGE-BANDWIDTH=983384,QUALITY=hd,FRAME-RATE=24,RESOLUTION=1280x532 /expires/1765623902829/srcIp/xxxxxxxc/pr/40/srcAg/UNKNOWN/ch/1676822812/ms/185.226.52.167/mid/10754960730152/type/3/sig/T8N9bXspsWc/ct/8/urls/185.226.53.179/clientType/13/zs/43/id/9464193092136/video/ #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=337936,AVERAGE-BANDWIDTH=201553,QUALITY=mobile,FRAME-RATE=24,RESOLUTION=256x106 /expires/1765623902829/srcIp/xxxxxxx/pr/40/srcAg/UNKNOWN/ch/1676822812/ms/185.226.52.167/mid/10754960730152/type/4/sig/emQkM4xuDpg/ct/8/urls/185.226.53.179/clientType/13/zs/43/id/9464193092136/video/` `import { Context, Meta, UrlResult, Format } from '../types'; import { Extractor } from './Extractor'; import { guessHeightFromPlaylist } from '../utils/height'; import { NotFoundError } from '../error'; export class VKResolver extends Extractor { public readonly id = 'vk'; public readonly label = 'VK'; public override readonly ttl = 10800000; // 3 hours private domains = ['vk.com', 'vkvideo.ru']; public supports(_: Context, url: URL): boolean { return this.domains.includes(url.host); } protected async extractInternal( ctx: Context, url: URL, meta: Meta ): Promise<UrlResult[]> { // --- extract query --- const query = new URLSearchParams(url.search); const oid = query.get('oid'); const videoId = query.get('id'); const videoList = query.get('list'); if (!oid || !videoId) { throw new NotFoundError('Missing VK oid or video id'); } // --- headers (needed only for al_video.php) --- const headers: Record<string, string> = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36', Referer: `https://${url.host}/`, Origin: `https://${url.host}`, 'X-Requested-With': 'XMLHttpRequest', }; // --- POST body --- const postData = new URLSearchParams({ act: 'show', al: '1', video: `${oid}_${videoId}`, }); if (videoList) { postData.set('list', videoList); postData.set('load_playlist', '1'); postData.set('module', 'direct'); postData.set('show_next', '1'); postData.set('playlist_id', `${oid}_-2`); } // --- request --- const response = await this.fetcher.textPost( ctx, new URL(`https://${url.host}/al_video.php`), postData.toString(), { headers } ); // --- parse JSON --- let json: any; try { json = JSON.parse(response.replace(/^<!--/, '')); } catch { throw new NotFoundError('VK response not JSON'); } // --- locate payload --- const payload = Array.isArray(json.payload?.[1]) ? json.payload[1] : []; const params = payload.find((p: any) => p?.player?.params)?.player?.params?.[0]; if (!params || typeof params !== 'object') { throw new NotFoundError('VK player params missing'); } // --- extract URLs --- const results: UrlResult[] = []; for (const [key, value] of Object.entries(params)) { if (!key.startsWith('url') || typeof value !== 'string') continue; let height: number | undefined; // key-based height (url720 → 720) const parsed = parseInt(key.replace('url', ''), 10); if (!Number.isNaN(parsed)) { height = parsed; } else { try { height = await guessHeightFromPlaylist( ctx, this.fetcher, new URL(value), url, { headers } ); } catch { height = undefined; } } results.push({ url: new URL(value + '.m3u8'), format: Format.hls, label: `VK ${height ?? 'auto'}p`, sourceId: this.id, ttl: this.ttl, meta: { ...meta, height }, requestHeaders: { Referer: `https://${url.host}/`, }, }); } if (!results.length) { throw new NotFoundError('No VK streams found'); } results.sort( (a, b) => (b.meta?.height ?? 0) - (a.meta?.height ?? 0) ); return [results[0]!]; } } ` You can run it yourself curl 'https://vkvideo.ru/al_video.php?act=show' \ -X POST \ -H 'User-Agent: Mozilla/5.0' \ -H 'Referer: https://vkvideo.ru/' \ -H 'Origin: https://vkvideo.ru' \ -H 'X-Requested-With: XMLHttpRequest' \ --data 'act=show&al=1&video=319533096_456239475' \ > response.json Than `iconv -f utf-8 -t utf-8 response.json | sed 's/\\u0000//g'`
GLlgGL commented 2025-12-10 14:37:03 +00:00 (Migrated from github.com)

I think is not possible even using mediaflow because of srcAg=CHROME
Is bounded with the request

The only way maybe this can work is via mpd

I think is not possible even using mediaflow because of srcAg=CHROME Is bounded with the request The only way maybe this can work is via mpd
GLlgGL commented 2025-12-24 15:07:52 +00:00 (Migrated from github.com)

I'm near but I don't get it what I'm f up...Those links generated from curl are working everywhere without mediaflow...

https://github.com/mhdzumair/mediaflow-proxy/pull/191

curl -s -X POST "https://vkvideo.ru/al_video.php?act=show" -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)" -H "Referer: https://vkvideo.ru/" -H "Origin: https://vkvideo.ru" -H "X-Requested-With: XMLHttpRequest" --data "act=show&al=1&video=319533096_456239517" | sed 's/^<!--//' | jq ' .payload[] | select(type=="array") | .[] | select(type=="object" and has("player")) | .player.params[0] | { url144, url240, url360, url480, url720, hls, hls_fmp4, dash_sep } '

Image
I'm near but I don't get it what I'm f up...Those links generated from curl are working everywhere without mediaflow... https://github.com/mhdzumair/mediaflow-proxy/pull/191 `curl -s -X POST "https://vkvideo.ru/al_video.php?act=show" -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)" -H "Referer: https://vkvideo.ru/" -H "Origin: https://vkvideo.ru" -H "X-Requested-With: XMLHttpRequest" --data "act=show&al=1&video=319533096_456239517" | sed 's/^<!--//' | jq ' .payload[] | select(type=="array") | .[] | select(type=="object" and has("player")) | .player.params[0] | { url144, url240, url360, url480, url720, hls, hls_fmp4, dash_sep } '` <img width="3012" height="1462" alt="Image" src="https://github.com/user-attachments/assets/f312ef6d-eeb1-4216-8801-b380ed59c20c" />
GLlgGL commented 2025-12-26 12:19:50 +00:00 (Migrated from github.com)

I found to make it work directly without mediaflow support...The problem was the headers flow

I found to make it work directly without mediaflow support...The problem was the headers flow
UrloMythus commented 2025-12-31 14:48:57 +00:00 (Migrated from github.com)

Sorry I saw the ping just now

Sorry I saw the ping just now
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Creepso/webstreamr-github#445
No description provided.