Skip to content

Instantly share code, notes, and snippets.

@alpgul
Created August 10, 2021 19:41
Show Gist options
  • Save alpgul/3f0bd8f57006e9fde15dbcd41b7dbf3e to your computer and use it in GitHub Desktop.
Save alpgul/3f0bd8f57006e9fde15dbcd41b7dbf3e to your computer and use it in GitHub Desktop.
Odnoklassniki Parser
// ==UserScript==
// @name odnoklassniki
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author AlpGul
// @include *
// @grant none
// ==/UserScript==
( function () {
'use strict';
function unescapeHtml( unsafe ) {
return unsafe
.replace( /&/g, "&" )
.replace( /&lt;/g, "<" )
.replace( /&gt;/g, ">" )
.replace( /&quot;/g, "\"" )
.replace( /&#039;/g, "'" )
}
const isNumString = ( str ) => !isNaN( Number( str ) );
function deepParseJson( jsonString ) {
// if not stringified json rather a simple string value then JSON.parse will throw error
// otherwise continue recursion
if ( typeof jsonString === 'string' ) {
if ( isNumString( jsonString ) ) {
// if a numeric string is received, return itself
// otherwise JSON.parse will convert it to a number
return jsonString;
}
try {
return deepParseJson( JSON.parse( jsonString ) );
} catch ( err ) {
return jsonString;
}
} else if ( Array.isArray( jsonString ) ) {
// if an array is received, map over the array and deepParse each value
return jsonString.map( val => deepParseJson( val ) );
} else if ( typeof jsonString === 'object' && jsonString !== null ) {
// if an object is received then deepParse each element in the object
// typeof null returns 'object' too, so we have to eliminate that
return Object.keys( jsonString ).reduce( ( obj, key ) => {
const val = jsonString[ key ];
obj[ key ] = isNumString( val ) ? val : deepParseJson( val );
return obj;
}, {} );
} else {
// otherwise return whatever was received
return jsonString;
}
}
class odnoklassniki {
static get _VALID_URL() {
return /https?:\/\/(?:(?:www|m|mobile)\.)?(?:odnoklassniki|ok)\.ru\/(?:video(?:embed)?\/|web-api\/video\/moviePlayer\/|live\/|dk\?.*?st\.mvId=)([\d-]+)/gi
}
constructor( firstProp ) {
this.firstProp = firstProp;
}
_extract_url( webpage ) {
let iframes = webpage.getElementsByTagName( 'iframe' );
for ( let i = 0; i < iframes.length; i++ ) {
const element = iframes[ i ];
const regex = /((?:https?:)?\/\/(?:odnoklassniki|ok)\.ru\/videoembed\/.+)/gi
if ( regex.test( element.src ) ) {
return element.src;
}
}
return false;
}
async _real_extract( url ) {
var _url = new URL( url );
let start_time = _url.searchParams.get( "fromTime" );
let video_id = this.constructor._VALID_URL.exec( url )[ 1 ];
let webpage = await fetch( `//ok.ru/video/${video_id}` ).then( ( res ) => {
return res.text();
} ).catch( function ( err ) {
console.warn( 'Something went wrong.', err );
} );
let error = document.getElementsByClassName( 'vp_video_stub_txt' );
if ( error.length > 0 ) throw new Error( 'vp_video_stub_txt' )
const regex = new RegExp( `data-options=(["\'])({.+?${video_id}.+?})(["\'])`, 'gi' )
let player = deepParseJson( unescapeHtml( regex.exec( webpage )[ 2 ] ) );
let flashvars = player[ 'flashvars' ];
let metadata = flashvars[ 'metadata' ];
if ( !metadata ) {
let data = {}
let st_location = flashvars[ 'location' ];
if ( st_location )
data[ 'st.location' ] = st_location
/* metadata = self._download_json(
compat_urllib_parse_unquote( flashvars[ 'metadataUrl' ] ),
video_id, 'Downloading metadata JSON',
data = urlencode_postdata( data ) )*/
}
let movie = metadata[ 'movie' ]
let provider = metadata[ 'provider' ];
let title = movie[ 'title' ];
let thumbnail = movie[ 'poster' ];
let duration = movie[ 'duration' ];
let author = metadata[ 'author' ];
let uploader_id = author[ 'id' ];
let uploader = author[ 'name' ];
let upload_date = null;
/* upload_date = unified_strdate( self._html_search_meta(
'ya:ovs:upload_date', webpage, 'upload date',
default = None ) )*/
let age_limit = null;
/*
age_limit = None
adult = self._html_search_meta(
'ya:ovs:adult', webpage, 'age limit',
default = None )
if adult:
age_limit = 18
if adult == 'true'
else 0*/
let like_count = metadata[ 'likeCount' ]
let info = {
'id': video_id,
'title': title,
'thumbnail': thumbnail,
'duration': duration,
'upload_date': upload_date,
'uploader': uploader,
'uploader_id': uploader_id,
'like_count': like_count,
'age_limit': age_limit,
'start_time': start_time,
}
if ( provider == 'USER_YOUTUBE' ) {
/* info.update( {
'_type': 'url_transparent',
'url': movie[ 'contentId' ],
} )
return info*/
}
if ( provider == 'LIVE_TV_APP' ) {
// info[ 'title' ] = self._live_title( title )
}
let quality //= qualities( ( '4', '0', '1', '2', '3', '5' ) )
let formats = [];
metadata[ 'videos' ].forEach( e => {
formats.push( {
'url': e[ 'url' ],
'ext': 'mp4',
'format_id': e[ 'name' ],
} )
} );
let m3u8_url = metadata[ 'hlsManifestUrl' ]
if ( m3u8_url )
formats.push( {
'm3u8_url': m3u8_url,
'm3u8_id': 'hls',
'ext': 'mp4',
'format': 'm3u8_native',
'video_id': video_id,
'fatal': false
} );
let dash_manifest = metadata[ 'metadataEmbedded' ];
if ( dash_manifest ) {
formats.push( {
dash_manifest
} );
}
for ( let fmt in formats ) {
if ( formats[ fmt ].hasOwnProperty( 'url' ) ) {
let fmt_type = /\btype[ /=](\d)/gi.exec( formats[ fmt ][ 'url' ] )[ 1 ];
}
// if ( fmt_type ) fmt[ 'quality' ] = quality( fmt_type )
}
m3u8_url = metadata[ 'hlsMasterPlaylistUrl' ];
if ( m3u8_url ) {
formats.push( {
'm3u8_url': m3u8_url,
'm3u8_id': 'hls',
'video_id': video_id,
'ext': 'mp4',
'fatal': false,
'entry_protocol': 'm3u8'
} );
}
let rtmp_url = metadata[ 'rtmpUrl' ];
if ( rtmp_url )
formats.push( {
'url': rtmp_url,
'format_id': 'rtmp',
'ext': 'flv',
} );
if ( !formats ) {
let payment_info = metadata[ 'paymentInfo' ];
if ( payment_info )
throw Error( 'This video is paid, subscribe to download it' );
}
info[ 'formats' ] = formats;
console.log( info )
return info
}
}
let app = new odnoklassniki();
let url = app._extract_url( window.document ) || window.location.href;
app._real_extract( url );
} )();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment