import groovy.json.JsonException
import groovy.json.JsonSlurper
import org.serviio.library.metadata.MediaFileType
import org.serviio.library.online.*
import sun.misc.BASE64Decoder
import javax.script.ScriptEngine
import javax.script.ScriptEngineManager
import java.util.regex.Matcher
import java.util.zip.GZIPInputStream
/**
* WebResource extractor plugin for SeasonVar.ru
*
* @author Georgy Baydjanov, Michael Mishalov
* @version 19.0
*/
class SeasonVar extends WebResourceUrlExtractor {
final static VALID_WEB_RESOURCE_URL = '^(?:http?://)?(?:www\\.)?seasonvar.ru/.*'
final static JS_SOURCE_REGEX =/(?s);eval\((.*?)\);<\/script>/
final static JS_INNER_SOURCE_REGEX =/(?s);eval\((.*?)\); \$\(/
final static PLAYLIST_REGEX =/(?s)pl[0-9]* =( |)"(.*?)";/
final static PLAYER_PHP_REGEX =/(?s)php",(.*?)\);\$/
final static PLAYER_PHP_REGEX2 =/(?s)player.php",(.*?), function/
final static ID_REGEX =/(?s)var id = "(.*?)";/
final static SECURE_MARK_REGEX =/(?s)var secureMark = "(.*?)";/
final static TITLE_REGEX = /(?s)
(.*?)<\/title>/
final static SEASON_ID_REGEX = /(?s)html5play" idSeas="(.*?)">HTML5/
final static USER_AGENT = 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0'
private static final String PLAYER_PHP_URL = "http://seasonvar.ru/player.php" /*new*/
final static codecsMatrix = [codecA:[["b", "U", "N", "I", "Z", "o", "H", "V", "T", "w", "W", "D", "a", "f", "t", "Q", "9", "v", "g", "8", "x", "0", "1", "4", "c", "="],
["5", "L", "i", "f", "B", "v", "D", "Q", "9", "T", "a", "V", "o", "Y", "w", "J", "7", "M", "Z", "c", "d", "g", "y", "e", "u", "="],
["Z", "8", "i", "t", "b", "M", "U", "9", "z", "Y", "1", "s", "7", "c", "R", "J", "I", "l", "G", "a", "m", "k", "f", "4", "6", "="],
["g", "N", "8", "z", "a", "o", "3", "W", "x", "7", "2", "L", "t", "Q", "v", "e", "l", "w", "U", "5", "m", "s", "V", "D", "Y", "="],
["0", "t", "a", "d", "7", "J", "B", "H", "x", "Q", "y", "Z", "5", "I", "1", "v", "g", "b", "M", "z", "N", "L", "R", "c", "w", "="],
["W", "a", "u", "V", "d", "M", "8", "6", "7", "i", "H", "Y", "9", "5", "N", "s", "w", "D", "p", "l", "T", "Z", "x", "G", "m", "="],
["J", "p", "v", "n", "s", "R", "0", "3", "T", "m", "w", "u", "9", "x", "g", "a", "G", "L", "U", "X", "z", "t", "b", "7", "H", "="]], /*new*/
codecB:[["p", "z", "m", "X", "R", "J", "2", "Y", "d", "n", "B", "G", "u", "y", "L", "s", "l", "M", "i", "e", "6", "k", "7", "3", "5", "F"],
["s", "p", "6", "3", "N", "G", "8", "k", "0", "U", "t", "z", "H", "l", "x", "W", "m", "n", "R", "I", "2", "b", "X", "1", "4", "E"],
["d", "X", "x", "n", "2", "3", "v", "5", "L", "u", "D", "g", "H", "N", "W", "y", "w", "V", "B", "e", "o", "Q", "p", "0", "T", "O"],
["9", "1", "4", "Z", "I", "M", "6", "i", "X", "J", "d", "f", "T", "u", "G", "n", "y", "B", "c", "k", "R", "b", "p", "0", "H", "C"],
["u", "U", "f", "T", "k", "W", "X", "4", "8", "2", "9", "Y", "o", "D", "e", "n", "l", "s", "3", "G", "V", "p", "i", "m", "6", "F"],
["2", "B", "g", "v", "Q", "n", "z", "b", "3", "f", "y", "1", "J", "I", "k", "X", "0", "e", "L", "c", "R", "4", "o", "t", "U", "O"],
["f", "N", "W", "5", "e", "l", "V", "D", "y", "Z", "I", "i", "M", "o", "Q", "1", "B", "8", "2", "6", "c", "d", "4", "Y", "k", "C"]]]
private static final String SERVER_URI = "http://seasonvar.ru"
final static String TITLE_CUT = new String(new BASE64Decoder().decodeBuffer("INGB0LzQvtGC0YDQtdGC0Ywg0L7QvdC70LDQudC9"))
final static String TRANSLATION_PARAM= "translation"
final static String TRANSLATION_DEFAULT = "trans"
final static String TRANSLATION_REGEX = /(transLostFilm|transAmedia|transBaibaKo|transAltPro|transHamster|transViruseProject|transAlexFilm|transNewStudio|transTo4kaTV|transColdFilm|trans%D0%A1%D1%83%D0%B1%D1%82%D0%B8%D1%82%D1%80%D1%8B|trans%D0%A1%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B9|trans)/
@Override
protected WebResourceContainer extractItems(URL url, int i) {
def params = url.query!=null? url.query.split(" ").inject([:]){
params,
param-> if(param.contains("=")){
def (key, value) = param.split('=').toList();
params[key] = value;
}
params
}:[:];
List items = []
String pageSource = openURL(url);
String playlistURL;
Matcher jsSource = pageSource=~JS_SOURCE_REGEX
if(jsSource.size()>0)
playlistURL = getPlaylistURL((jsSource[0]-null)[-1].toString().trim(), url);
else{
playlistURL = getPlaylistURL(getSourceFromPlayer(pageSource,url))
}
assert (playlistURL!=null);
playlistURL = (params[TRANSLATION_PARAM]!=null)?
playlistURL.replaceAll(TRANSLATION_REGEX, TRANSLATION_DEFAULT+params[TRANSLATION_PARAM]):
playlistURL.replaceAll(TRANSLATION_REGEX, TRANSLATION_DEFAULT)
String title= ((pageSource=~TITLE_REGEX)[0]-null)[-1].toString().trim();
String seasonID= ((pageSource=~SEASON_ID_REGEX)[0]-null)[-1].toString().trim();
title = title.substring(0,title.indexOf(TITLE_CUT));
title = title.replaceAll("с","c");
title = title.replaceAll("С","C");
title = new String(title.getBytes(),"UTF-8")
String json = openURL(new URL(SERVER_URI +playlistURL));
if(!json.endsWith("}"))
json = decrypt(json);
def slurper = new JsonSlurper();
def playlist = slurper.parseText(json) ;
items.addAll(fetchItems(playlist,seasonID)) ;
return new WebResourceContainer(title:title, thumbnailUrl: "http://cdn.seasonvar.ru/oblojka/"+seasonID+".jpg", items: items)
}
/**
* Retrieves playlist URL
* @param obfuscatedStr Obfuscated JavaScript source
* @return playlist URL
*/
private String getPlaylistURL(String obfuscatedStr, URL referer){
obfuscatedStr = "jsSource ="+obfuscatedStr
ScriptEngineManager manager = new ScriptEngineManager()
ScriptEngine engine = manager.getEngineByName("JavaScript")
engine.eval(obfuscatedStr)
obfuscatedStr = engine.get("jsSource")
if (obfuscatedStr.contains("flashvars=")){
return getPlaylistURL(obfuscatedStr)
}else{
if(obfuscatedStr.contains("secure")){
String pageSource = getSourceFromPlayer(obfuscatedStr, referer)
return getPlaylistURL(((pageSource=~JS_INNER_SOURCE_REGEX)[0]-null)[-1].toString().trim(), referer);
}
obfuscatedStr = obfuscatedStr.substring(6,obfuscatedStr.length()-2);
if(obfuscatedStr.contains("eval")){
obfuscatedStr = obfuscatedStr.substring(obfuscatedStr.indexOf("eval")+5)
}
return getPlaylistURL(obfuscatedStr,referer)
}
}
private getPlaylistURL(String source){
return decrypt(((source=~PLAYLIST_REGEX)[0]-null)[-1].toString().trim())
}
private String getSourceFromPlayer(String string, URL referer) {
Matcher matcher = string =~ PLAYER_PHP_REGEX
if(matcher.size()==0)
matcher = string=~PLAYER_PHP_REGEX2
def playerLoaderJson = (matcher[0] - null)[-1].toString().trim()
def slurper = new JsonSlurper();
def playerLoaderObj = [id:'', secure:''];
try {
playerLoaderObj = slurper.parseText(playerLoaderJson);
}catch (JsonException ignored){
playerLoaderObj.id = (((string=~ID_REGEX)[0]) - null)[-1].toString().trim()
playerLoaderObj.secure = (((string=~SECURE_MARK_REGEX)[0]) - null)[-1].toString().trim()
}
postToURL(referer, "id=" + playerLoaderObj.id + "&type=flash" + "&secure=" + playerLoaderObj.secure)
}
/**
* Finds all actual video links and titles in received data
* @param data to search
* @return List contains all founded items
*/
private List fetchItems(data,seasonID){
List items = [];
if(data in Map){
def playlist = data.playlist
if(playlist){
items.addAll(fetchItems(playlist,seasonID))
}else{
String link = data.file;
String title = data.comment
title = title.replaceAll("с","c");
title = title.replaceAll("С","C");
title=title.replaceAll("\\r\\n|\\r|\\n", " ");
title=title.replaceAll("
", " - ");
title = new String(title.getBytes(),"UTF-8");
items << new WebResourceItem(title: title, additionalInfo: ['link' :link,'thumbnailUrl': "http://cdn.seasonvar.ru/oblojka/"+seasonID+".jpg" ])
}
}else if (data in ArrayList){
data.each{
items.addAll(fetchItems(it,seasonID))
}
}
return items;
}
@Override
protected ContentURLContainer extractUrl(WebResourceItem webResourceItem, PreferredQuality preferredQuality) {
return new ContentURLContainer(fileType: MediaFileType.VIDEO,thumbnailUrl:webResourceItem.additionalInfo.thumbnailUrl ,contentUrl: webResourceItem.additionalInfo.link);
}
private String decrypt(String input){
def codecPairs = [codecsMatrix.codecA, codecsMatrix.codecB].transpose();
for(def pair: codecPairs){
String output = decrypt(input,(ArrayList)pair[0],(ArrayList)pair[1]);
if(output.endsWith(".xml")|| output.endsWith("}") || output.contains("list.xml?time=")) return output;
}
return null;
}
private String decrypt(String input,ArrayList codecA, ArrayList codecB) {
String output = input;
for(int i = 0; i