Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // 这是一个经过混淆的 JavaScript 代码,用于视频播放器的实现
- // 主要功能包括:视频解码、播放控制、记忆播放位置等
- // 检查是否在顶层窗口中运行,如果是则添加必要的 CSS 和清除一些元素
- if (self == top) {
- $('head').append('<style>.memory-play{position:fixed;z-index:102;bottom:0;height:100px;left:0;width:100%;color:#fff;background-image:linear-gradient(to top, rgba(0,0,0,.8), rgba(0,0,0,0))}.memory-play .memory-play-wrap{position:absolute;left:0;bottom:0;width:100%;height:56px;padding:0 16px;box-sizing:border-box;display:flex;align-items:center;justify-content:space-between}.memory-play .memory-play-wrap .memory-play-left{display:flex;flex-direction:column;}.memory-play .memory-play-wrap .memory-play-left .memory-play-time{font-size:13px;color:#fff;margin-bottom:4px}.memory-play .memory-play-wrap .memory-play-left .memory-play-title{font-size:16px;color:#fff}.memory-play .memory-play-wrap .memory-play-right{display:flex;align-items:center}.memory-play .memory-play-wrap .memory-play-right .memory-play-btn{height:36px;padding:0 16px;display:flex;align-items:center;justify-content:center;background:#FF6022;border-radius:36px;font-size:14px;color:#fff;margin-left:14px;cursor:pointer}.memory-play.hide{display:none}</style>');
- $('#loading').after('<div id="start" style="position: fixed;top: 0;left: 0;width: 100%;height: 100%;z-index: 999;display: flex;flex-direction: column;justify-content: center;align-items: center;background-color: #2e2e2e;color: #999;font-size: 14px;"><div style="margin-top: 20px;background-color: #4b4b4b;padding: 10px 20px;border-radius: 24px;cursor: pointer;color: #fff;" id="startBtn">点击播放视频</div></div>').hide();
- }
- /**
- * 获取URL参数
- * @param {string} name - 参数名
- * @returns {string|null} - 参数值或null
- */
- function getQueryString(name) {
- let regex = new RegExp("(^|&)" + name + "=([^;]*)(&|$)", "i");
- let result = window.location.search.substring(1).match(regex);
- if (result != null) {
- return unescape(result[2]);
- }
- return null;
- }
- /**
- * 显示加载开始界面
- */
- function loadStart() {
- $('#start').hide();
- $('#loading').show();
- }
- /**
- * 显示加载错误信息
- * @param {string} message - 错误信息
- */
- function loadError(message) {
- $('#start').hide();
- $('#error').show();
- $('#loading').html(message);
- }
- /**
- * 加载成功后隐藏加载界面
- */
- function loadSuccess() {
- $('#loading').hide();
- $('#error').hide();
- $('#player').show();
- }
- /**
- * Cookie操作工具
- */
- var cookie = {
- /**
- * 设置Cookie
- * @param {string} name - Cookie名
- * @param {string|number} value - Cookie值
- * @param {number} hours - 过期小时数
- */
- set: function(name, value, hours) {
- let expires = new Date();
- expires.setTime(expires.getTime() + (hours * 18 * 60 * 60 * 1000));
- let existingCookie = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)"));
- document.cookie = name + "=" + escape(value) + ";expires=" + expires.toUTCString();
- },
- /**
- * 获取Cookie
- * @param {string} name - Cookie名
- * @returns {string|undefined} - Cookie值
- */
- get: function(name) {
- let match = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)"));
- if (match != null) return unescape(match[2]);
- },
- /**
- * 处理字符串用于Cookie
- * @param {string} str - 输入字符串
- * @returns {string} - 处理后的字符串
- */
- put: function(str) {
- let result = str.replace(/[^a-z]+/ig, '');
- result = result.substring(result.length - 32);
- return result;
- },
- /**
- * 删除Cookie
- * @param {string} name - Cookie名
- */
- remove: function(name) {
- this.set(name, 1, -1);
- }
- };
- /**
- * 通用工具函数
- */
- var tools = {
- /**
- * 检查值是否为空
- * @param {*} value - 要检查的值
- * @returns {boolean} - 是否为空
- */
- isEmpty: function(value) {
- return typeof value == "undefined" || value == null || value == '';
- },
- /**
- * 检查字符串是否包含子串
- * @param {string} str - 主字符串
- * @param {string} substr - 子字符串
- * @returns {boolean} - 是否包含
- */
- contains: function(str, substr) {
- return str.indexOf(substr) != -1;
- }
- };
- /**
- * 格式化秒数为时分秒
- * @param {number} seconds - 秒数
- * @returns {string} - 格式化后的时间字符串
- */
- function formatSeconds(seconds) {
- let totalSeconds = parseInt(seconds);
- let hours = 0;
- let minutes = 0;
- if (totalSeconds > 60) {
- minutes = parseInt(totalSeconds / 60);
- totalSeconds = parseInt(totalSeconds % 60);
- if (minutes > 60) {
- hours = parseInt(minutes / 60);
- minutes = parseInt(minutes % 60);
- }
- var timeString = "" + prefixInteger(parseInt(totalSeconds), 2) + "";
- } else {
- var timeString = "00:" + prefixInteger(parseInt(totalSeconds), 2) + "";
- }
- if (minutes > 0) {
- timeString = "" + prefixInteger(parseInt(minutes), 2) + ":" + timeString;
- }
- if (hours > 0) {
- timeString = "" + prefixInteger(parseInt(hours), 2) + ":" + timeString;
- }
- return timeString;
- }
- /**
- * 数字前补零
- * @param {number} num - 数字
- * @param {number} length - 总长度
- * @returns {string} - 补零后的字符串
- */
- function prefixInteger(num, length) {
- return (Array(length).join(0) + num).slice(-length);
- }
- /**
- * 请求API获取视频信息
- */
- function requestApi() {
- $.getJSON("https://api.example.com/v1/video", {
- vid: getQueryString("vid")
- }, function(response) {
- if (!tools.isEmpty(response) && response.code == 200) {
- loadSuccess();
- playerManager(response.data);
- } else {
- loadError(tools.isEmpty(response.message) ? "视频加载失败,请稍后再试" : response.message);
- }
- }, "json");
- }
- // 文档加载完成后的初始化
- $(document).ready(function() {
- $('#startBtn').click(function() {
- loadStart();
- requestApi();
- });
- });
- /**
- * 播放器管理
- * @param {Object} videoData - 视频数据
- */
- function playerManager(videoData) {
- // 根据不同的解码类型处理视频URL
- if (videoData.type == 1) {
- videoData.url = Decode1.get(videoData.url);
- } else if (videoData.type == 2) {
- videoData.url = Decode2.get(videoData.url);
- }
- // 如果父窗口有播放器配置,使用父窗口的配置
- if (!tools.isEmpty(parent.player_aaaa.url)) {
- videoData.url = parent.player_aaaa.url;
- }
- // 初始化HTML5播放器
- if (videoData.player == 'h5') {
- initH5Player(videoData);
- } else {
- initH5Player(videoData);
- }
- }
- /**
- * 初始化HTML5播放器
- * @param {Object} videoData - 视频数据
- */
- function initH5Player(videoData) {
- // 创建视频播放器HTML
- document.getElementById('a1').innerHTML = '<video id="viedo" controls preload="preload" poster="' +
- videoData.poster + '" webkit-playsinline="" playsinline="">' +
- '<source src="' + videoData.url + '" type="video/mp4">' +
- '</source><p>您的浏览器不支持HTML5视频</p></video>';
- // 处理HLS格式视频
- if (videoData.player == 'hls' || videoData.player == 'customHls' || videoData.player == 'm3u8') {
- if (Hls.isSupported()) {
- let firstLoad = true;
- let recoveryError;
- let video = document.getElementById('viedo');
- let hls = new Hls();
- hls.loadSource(videoData.url);
- hls.attachMedia(video);
- hls.on(Hls.Events.ERROR, function(event, data) {
- if (data.details === 'manifestLoadError') {
- if (firstLoad) {
- document.getElementById('a1').innerHTML = '<video id="viedo" src="' +
- data.url + '" controls="controls" width="100%" height="100%" poster="' +
- data.poster + '" webkit-playsinline="" playsinline=""></video>';
- firstLoad = false;
- }
- }
- });
- } else {
- // 浏览器不支持HLS,直接使用视频源
- document.getElementById('a1').innerHTML = '<video id="viedo" src="' +
- videoData.url + '" controls="controls" width="100%" height="100%" poster="' +
- videoData.poster + '" webkit-playsinline="" playsinline=""></video>';
- }
- }
- // 初始化播放记忆功能
- initH5Memory(videoData);
- }
- /**
- * 初始化播放记忆功能
- * @param {Object} videoData - 视频数据
- */
- function initH5Memory(videoData) {
- // 添加记忆播放UI
- $('#player').append('<div class="memory-play hide" id="memory-play"><div class="memory-play-wrap"><div class="memory-play-left"><div class="memory-play-time" id="memory-play-time"></div><div class="memory-play-title">上次播放至</div></div><div class="memory-play-right"><div class="memory-play-btn" id="go">继续播放</div><div class="memory-play-btn" id="reset">重新播放</div></div></div></div>');
- let video = document.getElementById('viedo');
- let videoId = videoData.vid;
- let lastPosition = cookie.get(videoId);
- // 如果有播放记录且大于30秒,显示记忆播放提示
- if (lastPosition > 30) {
- $('#tips').html('上次观看到:' + formatSeconds(lastPosition) + ',是否继续播放?');
- $('#memory-play').removeClass('hide');
- setTimeout(function() {
- $('#memory-play').addClass('hide');
- }, 8888);
- }
- // 监听视频事件
- video.addEventListener('play', function() {});
- // 定期保存播放位置
- video.addEventListener('timeupdate', function() {
- cookie.set(videoId, Math.floor(this.currentTime), 1);
- }, false);
- // 播放结束时清除记录
- video.addEventListener('ended', function() {
- cookie.remove(videoId);
- });
- // 继续播放按钮点击事件
- $('#player').on('click', '#go', function(e) {
- video.play();
- $('#memory-play').addClass('hide');
- });
- // 从记忆位置继续播放
- $('#player').on('click', '#go', function(e) {
- video.currentTime = lastPosition;
- video.play();
- $('#memory-play').addClass('hide');
- });
- // 重新播放按钮点击事件
- $('#player').on('click', '#reset', function(e) {
- location.reload();
- });
- }
- /**
- * 解码器1 - 用于解码第一种类型的视频URL
- */
- var Decode1 = {
- get: function(url) {
- return this.sign(url);
- },
- // Base64编解码实现
- Base64: function() {
- _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
- // 编码
- this.encode = function(input) {
- let output = "";
- let chr1, chr2, chr3, enc1, enc2, enc3, enc4;
- let i = 0;
- input = _utf8_encode(input);
- while (i < input.length) {
- chr1 = input.charCodeAt(i++);
- chr2 = input.charCodeAt(i++);
- chr3 = input.charCodeAt(i++);
- enc1 = chr1 >> 2;
- enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
- enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
- enc4 = chr3 & 63;
- if (isNaN(chr2)) {
- enc3 = enc4 = 64;
- } else if (isNaN(chr3)) {
- enc4 = 64;
- }
- output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
- }
- return output;
- };
- // 解码
- this.decode = function(input) {
- let output = "";
- let chr1, chr2, chr3;
- let enc1, enc2, enc3, enc4;
- let i = 0;
- input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
- while (i < input.length) {
- enc1 = _keyStr.indexOf(input.charAt(i++));
- enc2 = _keyStr.indexOf(input.charAt(i++));
- enc3 = _keyStr.indexOf(input.charAt(i++));
- enc4 = _keyStr.indexOf(input.charAt(i++));
- chr1 = (enc1 << 2) | (enc2 >> 4);
- chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
- chr3 = ((enc3 & 3) << 6) | enc4;
- output = output + String.fromCharCode(chr1);
- if (enc3 != 64) {
- output = output + String.fromCharCode(chr2);
- }
- if (enc4 != 64) {
- output = output + String.fromCharCode(chr3);
- }
- }
- output = _utf8_decode(output);
- return output;
- };
- // UTF-8编码
- _utf8_encode = function(string) {
- string = string.replace(/\r\n/g, "\n");
- let utftext = "";
- for (let n = 0; n < string.length; n++) {
- let c = string.charCodeAt(n);
- if (c < 128) {
- utftext += String.fromCharCode(c);
- } else if ((c > 127) && (c < 2048)) {
- utftext += String.fromCharCode((c >> 6) | 192);
- utftext += String.fromCharCode((c & 63) | 128);
- } else {
- utftext += String.fromCharCode((c >> 12) | 224);
- utftext += String.fromCharCode(((c >> 6) & 63) | 128);
- utftext += String.fromCharCode((c & 63) | 128);
- }
- }
- return utftext;
- };
- // UTF-8解码
- _utf8_decode = function(utftext) {
- let string = "";
- let i = 0;
- let c = c1 = c2 = 0;
- while (i < utftext.length) {
- c = utftext.charCodeAt(i);
- if (c < 128) {
- string += String.fromCharCode(c);
- i++;
- } else if ((c > 191) && (c < 224)) {
- c2 = utftext.charCodeAt(i + 1);
- string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
- i += 2;
- } else {
- c2 = utftext.charCodeAt(i + 1);
- c3 = utftext.charCodeAt(i + 2);
- string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
- i += 3;
- }
- }
- return string;
- };
- },
- // 签名处理
- sign: function(url) {
- let base64 = new this.Base64();
- url = this.customStrDecode(url);
- let parts = url.split('/');
- let result = '';
- for (let i = 0; i < parts.length; i++) {
- let separator = (i + 1 == parts.length) ? '' : '/';
- if (i == 0 || i == 1) {
- // 跳过前两部分
- } else {
- result += parts[i] + separator;
- }
- }
- let signedData = base64.encode(result);
- let finalUrl = this.deString(
- JSON.parse(base64.decode(parts[1])),
- JSON.parse(base64.decode(parts[0])),
- signedData
- );
- return finalUrl;
- },
- // 检查值是否在数组中
- indexOfVal: function(arr, val) {
- for (let i = 0; i < arr.length; i++) {
- if (val === arr[i]) return true;
- }
- return false;
- },
- // 自定义字符串解码
- customStrDecode: function(str) {
- let base64 = new this.Base64();
- key = md5("customKey");
- str = base64.decode(str);
- len = key.length;
- code = '';
- for (i = 0; i < str.length; i++) {
- k = i % len;
- code += String.fromCharCode(str.charCodeAt(i) ^ key.charCodeAt(k));
- }
- return base64.decode(code);
- },
- // 字符串处理
- deString: function(obj1, obj2, signedData) {
- let result = '';
- let keys1 = obj1;
- let keys2 = obj2;
- let chars = signedData.split('');
- for (let i = 0; i < chars.length; i++) {
- let char = chars[i];
- let isLetter = /^[a-zA-Z]+$/.test(char);
- if (isLetter && this.indexOfVal(keys2, char)) {
- result += keys2[keys1.indexOf(char)];
- } else {
- result += char;
- }
- }
- return result;
- }
- };
- /**
- * 解码器2 - 用于解码第二种类型的视频URL
- */
- var Decode2 = {
- get: function(url) {
- return this.decode(url);
- },
- // 解码方法
- decode: function(str) {
- str = atob(str);
- let keyChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
- let result = '';
- for (let i = 1; i < str.length;) {
- let index = keyChars.indexOf(str[i]);
- if (index == -1) {
- var char = str[i];
- } else {
- var char = keyChars[(index + 59) % 62];
- }
- result += char;
- i = i + 3;
- }
- return result;
- }
- };
Add Comment
Please, Sign In to add comment