Created
August 10, 2021 19:41
-
-
Save alpgul/3f0bd8f57006e9fde15dbcd41b7dbf3e to your computer and use it in GitHub Desktop.
Odnoklassniki Parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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( /</g, "<" ) | |
.replace( />/g, ">" ) | |
.replace( /"/g, "\"" ) | |
.replace( /'/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