Guest User

Untitled

a guest
Apr 15th, 2025
193
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // 这是一个经过混淆的 JavaScript 代码,用于视频播放器的实现
  2. // 主要功能包括:视频解码、播放控制、记忆播放位置等
  3.  
  4. // 检查是否在顶层窗口中运行,如果是则添加必要的 CSS 和清除一些元素
  5. if (self == top) {
  6.     $('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>');
  7.     $('#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();
  8. }
  9.  
  10. /**
  11.  * 获取URL参数
  12.  * @param {string} name - 参数名
  13.  * @returns {string|null} - 参数值或null
  14.  */
  15. function getQueryString(name) {
  16.     let regex = new RegExp("(^|&)" + name + "=([^;]*)(&|$)", "i");
  17.     let result = window.location.search.substring(1).match(regex);
  18.     if (result != null) {
  19.         return unescape(result[2]);
  20.     }
  21.     return null;
  22. }
  23.  
  24. /**
  25.  * 显示加载开始界面
  26.  */
  27. function loadStart() {
  28.     $('#start').hide();
  29.     $('#loading').show();
  30. }
  31.  
  32. /**
  33.  * 显示加载错误信息
  34.  * @param {string} message - 错误信息
  35.  */
  36. function loadError(message) {
  37.     $('#start').hide();
  38.     $('#error').show();
  39.     $('#loading').html(message);
  40. }
  41.  
  42. /**
  43.  * 加载成功后隐藏加载界面
  44.  */
  45. function loadSuccess() {
  46.     $('#loading').hide();
  47.     $('#error').hide();
  48.     $('#player').show();
  49. }
  50.  
  51. /**
  52.  * Cookie操作工具
  53.  */
  54. var cookie = {
  55.     /**
  56.      * 设置Cookie
  57.      * @param {string} name - Cookie名
  58.      * @param {string|number} value - Cookie值
  59.      * @param {number} hours - 过期小时数
  60.      */
  61.     set: function(name, value, hours) {
  62.         let expires = new Date();
  63.         expires.setTime(expires.getTime() + (hours * 18 * 60 * 60 * 1000));
  64.         let existingCookie = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)"));
  65.         document.cookie = name + "=" + escape(value) + ";expires=" + expires.toUTCString();
  66.     },
  67.    
  68.     /**
  69.      * 获取Cookie
  70.      * @param {string} name - Cookie名
  71.      * @returns {string|undefined} - Cookie值
  72.      */
  73.     get: function(name) {
  74.         let match = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)"));
  75.         if (match != null) return unescape(match[2]);
  76.     },
  77.    
  78.     /**
  79.      * 处理字符串用于Cookie
  80.      * @param {string} str - 输入字符串
  81.      * @returns {string} - 处理后的字符串
  82.      */
  83.     put: function(str) {
  84.         let result = str.replace(/[^a-z]+/ig, '');
  85.         result = result.substring(result.length - 32);
  86.         return result;
  87.     },
  88.    
  89.     /**
  90.      * 删除Cookie
  91.      * @param {string} name - Cookie名
  92.      */
  93.     remove: function(name) {
  94.         this.set(name, 1, -1);
  95.     }
  96. };
  97.  
  98. /**
  99.  * 通用工具函数
  100.  */
  101. var tools = {
  102.     /**
  103.      * 检查值是否为空
  104.      * @param {*} value - 要检查的值
  105.      * @returns {boolean} - 是否为空
  106.      */
  107.     isEmpty: function(value) {
  108.         return typeof value == "undefined" || value == null || value == '';
  109.     },
  110.    
  111.     /**
  112.      * 检查字符串是否包含子串
  113.      * @param {string} str - 主字符串
  114.      * @param {string} substr - 子字符串
  115.      * @returns {boolean} - 是否包含
  116.      */
  117.     contains: function(str, substr) {
  118.         return str.indexOf(substr) != -1;
  119.     }
  120. };
  121.  
  122. /**
  123.  * 格式化秒数为时分秒
  124.  * @param {number} seconds - 秒数
  125.  * @returns {string} - 格式化后的时间字符串
  126.  */
  127. function formatSeconds(seconds) {
  128.     let totalSeconds = parseInt(seconds);
  129.     let hours = 0;
  130.     let minutes = 0;
  131.    
  132.     if (totalSeconds > 60) {
  133.         minutes = parseInt(totalSeconds / 60);
  134.         totalSeconds = parseInt(totalSeconds % 60);
  135.        
  136.         if (minutes > 60) {
  137.             hours = parseInt(minutes / 60);
  138.             minutes = parseInt(minutes % 60);
  139.         }
  140.        
  141.         var timeString = "" + prefixInteger(parseInt(totalSeconds), 2) + "";
  142.     } else {
  143.         var timeString = "00:" + prefixInteger(parseInt(totalSeconds), 2) + "";
  144.     }
  145.    
  146.     if (minutes > 0) {
  147.         timeString = "" + prefixInteger(parseInt(minutes), 2) + ":" + timeString;
  148.     }
  149.    
  150.     if (hours > 0) {
  151.         timeString = "" + prefixInteger(parseInt(hours), 2) + ":" + timeString;
  152.     }
  153.    
  154.     return timeString;
  155. }
  156.  
  157. /**
  158.  * 数字前补零
  159.  * @param {number} num - 数字
  160.  * @param {number} length - 总长度
  161.  * @returns {string} - 补零后的字符串
  162.  */
  163. function prefixInteger(num, length) {
  164.     return (Array(length).join(0) + num).slice(-length);
  165. }
  166.  
  167. /**
  168.  * 请求API获取视频信息
  169.  */
  170. function requestApi() {
  171.     $.getJSON("https://api.example.com/v1/video", {
  172.         vid: getQueryString("vid")
  173.     }, function(response) {
  174.         if (!tools.isEmpty(response) && response.code == 200) {
  175.             loadSuccess();
  176.             playerManager(response.data);
  177.         } else {
  178.             loadError(tools.isEmpty(response.message) ? "视频加载失败,请稍后再试" : response.message);
  179.         }
  180.     }, "json");
  181. }
  182.  
  183. // 文档加载完成后的初始化
  184. $(document).ready(function() {
  185.     $('#startBtn').click(function() {
  186.         loadStart();
  187.         requestApi();
  188.     });
  189. });
  190.  
  191. /**
  192.  * 播放器管理
  193.  * @param {Object} videoData - 视频数据
  194.  */
  195. function playerManager(videoData) {
  196.     // 根据不同的解码类型处理视频URL
  197.     if (videoData.type == 1) {
  198.         videoData.url = Decode1.get(videoData.url);
  199.     } else if (videoData.type == 2) {
  200.         videoData.url = Decode2.get(videoData.url);
  201.     }
  202.    
  203.     // 如果父窗口有播放器配置,使用父窗口的配置
  204.     if (!tools.isEmpty(parent.player_aaaa.url)) {
  205.         videoData.url = parent.player_aaaa.url;
  206.     }
  207.    
  208.     // 初始化HTML5播放器
  209.     if (videoData.player == 'h5') {
  210.         initH5Player(videoData);
  211.     } else {
  212.         initH5Player(videoData);
  213.     }
  214. }
  215.  
  216. /**
  217.  * 初始化HTML5播放器
  218.  * @param {Object} videoData - 视频数据
  219.  */
  220. function initH5Player(videoData) {
  221.     // 创建视频播放器HTML
  222.     document.getElementById('a1').innerHTML = '<video id="viedo" controls preload="preload" poster="' +
  223.         videoData.poster + '" webkit-playsinline="" playsinline="">' +
  224.         '<source src="' + videoData.url + '" type="video/mp4">' +
  225.         '</source><p>您的浏览器不支持HTML5视频</p></video>';
  226.    
  227.     // 处理HLS格式视频
  228.     if (videoData.player == 'hls' || videoData.player == 'customHls' || videoData.player == 'm3u8') {
  229.         if (Hls.isSupported()) {
  230.             let firstLoad = true;
  231.             let recoveryError;
  232.             let video = document.getElementById('viedo');
  233.             let hls = new Hls();
  234.            
  235.             hls.loadSource(videoData.url);
  236.             hls.attachMedia(video);
  237.            
  238.             hls.on(Hls.Events.ERROR, function(event, data) {
  239.                 if (data.details === 'manifestLoadError') {
  240.                     if (firstLoad) {
  241.                         document.getElementById('a1').innerHTML = '<video id="viedo" src="' +
  242.                             data.url + '" controls="controls" width="100%" height="100%" poster="' +
  243.                             data.poster + '" webkit-playsinline="" playsinline=""></video>';
  244.                         firstLoad = false;
  245.                     }
  246.                 }
  247.             });
  248.         } else {
  249.             // 浏览器不支持HLS,直接使用视频源
  250.             document.getElementById('a1').innerHTML = '<video id="viedo" src="' +
  251.                 videoData.url + '" controls="controls" width="100%" height="100%" poster="' +
  252.                 videoData.poster + '" webkit-playsinline="" playsinline=""></video>';
  253.         }
  254.     }
  255.    
  256.     // 初始化播放记忆功能
  257.     initH5Memory(videoData);
  258. }
  259.  
  260. /**
  261.  * 初始化播放记忆功能
  262.  * @param {Object} videoData - 视频数据
  263.  */
  264. function initH5Memory(videoData) {
  265.     // 添加记忆播放UI
  266.     $('#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>');
  267.    
  268.     let video = document.getElementById('viedo');
  269.     let videoId = videoData.vid;
  270.     let lastPosition = cookie.get(videoId);
  271.    
  272.     // 如果有播放记录且大于30秒,显示记忆播放提示
  273.     if (lastPosition > 30) {
  274.         $('#tips').html('上次观看到:' + formatSeconds(lastPosition) + ',是否继续播放?');
  275.         $('#memory-play').removeClass('hide');
  276.        
  277.         setTimeout(function() {
  278.             $('#memory-play').addClass('hide');
  279.         }, 8888);
  280.     }
  281.    
  282.     // 监听视频事件
  283.     video.addEventListener('play', function() {});
  284.    
  285.     // 定期保存播放位置
  286.     video.addEventListener('timeupdate', function() {
  287.         cookie.set(videoId, Math.floor(this.currentTime), 1);
  288.     }, false);
  289.    
  290.     // 播放结束时清除记录
  291.     video.addEventListener('ended', function() {
  292.         cookie.remove(videoId);
  293.     });
  294.    
  295.     // 继续播放按钮点击事件
  296.     $('#player').on('click', '#go', function(e) {
  297.         video.play();
  298.         $('#memory-play').addClass('hide');
  299.     });
  300.    
  301.     // 从记忆位置继续播放
  302.     $('#player').on('click', '#go', function(e) {
  303.         video.currentTime = lastPosition;
  304.         video.play();
  305.         $('#memory-play').addClass('hide');
  306.     });
  307.    
  308.     // 重新播放按钮点击事件
  309.     $('#player').on('click', '#reset', function(e) {
  310.         location.reload();
  311.     });
  312. }
  313.  
  314. /**
  315.  * 解码器1 - 用于解码第一种类型的视频URL
  316.  */
  317. var Decode1 = {
  318.     get: function(url) {
  319.         return this.sign(url);
  320.     },
  321.    
  322.     // Base64编解码实现
  323.     Base64: function() {
  324.         _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  325.        
  326.         // 编码
  327.         this.encode = function(input) {
  328.             let output = "";
  329.             let chr1, chr2, chr3, enc1, enc2, enc3, enc4;
  330.             let i = 0;
  331.            
  332.             input = _utf8_encode(input);
  333.            
  334.             while (i < input.length) {
  335.                 chr1 = input.charCodeAt(i++);
  336.                 chr2 = input.charCodeAt(i++);
  337.                 chr3 = input.charCodeAt(i++);
  338.                
  339.                 enc1 = chr1 >> 2;
  340.                 enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
  341.                 enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
  342.                 enc4 = chr3 & 63;
  343.                
  344.                 if (isNaN(chr2)) {
  345.                     enc3 = enc4 = 64;
  346.                 } else if (isNaN(chr3)) {
  347.                     enc4 = 64;
  348.                 }
  349.                
  350.                 output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
  351.             }
  352.            
  353.             return output;
  354.         };
  355.        
  356.         // 解码
  357.         this.decode = function(input) {
  358.             let output = "";
  359.             let chr1, chr2, chr3;
  360.             let enc1, enc2, enc3, enc4;
  361.             let i = 0;
  362.            
  363.             input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
  364.            
  365.             while (i < input.length) {
  366.                 enc1 = _keyStr.indexOf(input.charAt(i++));
  367.                 enc2 = _keyStr.indexOf(input.charAt(i++));
  368.                 enc3 = _keyStr.indexOf(input.charAt(i++));
  369.                 enc4 = _keyStr.indexOf(input.charAt(i++));
  370.                
  371.                 chr1 = (enc1 << 2) | (enc2 >> 4);
  372.                 chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
  373.                 chr3 = ((enc3 & 3) << 6) | enc4;
  374.                
  375.                 output = output + String.fromCharCode(chr1);
  376.                
  377.                 if (enc3 != 64) {
  378.                     output = output + String.fromCharCode(chr2);
  379.                 }
  380.                 if (enc4 != 64) {
  381.                     output = output + String.fromCharCode(chr3);
  382.                 }
  383.             }
  384.            
  385.             output = _utf8_decode(output);
  386.            
  387.             return output;
  388.         };
  389.        
  390.         // UTF-8编码
  391.         _utf8_encode = function(string) {
  392.             string = string.replace(/\r\n/g, "\n");
  393.             let utftext = "";
  394.            
  395.             for (let n = 0; n < string.length; n++) {
  396.                 let c = string.charCodeAt(n);
  397.                
  398.                 if (c < 128) {
  399.                     utftext += String.fromCharCode(c);
  400.                 } else if ((c > 127) && (c < 2048)) {
  401.                     utftext += String.fromCharCode((c >> 6) | 192);
  402.                     utftext += String.fromCharCode((c & 63) | 128);
  403.                 } else {
  404.                     utftext += String.fromCharCode((c >> 12) | 224);
  405.                     utftext += String.fromCharCode(((c >> 6) & 63) | 128);
  406.                     utftext += String.fromCharCode((c & 63) | 128);
  407.                 }
  408.             }
  409.            
  410.             return utftext;
  411.         };
  412.        
  413.         // UTF-8解码
  414.         _utf8_decode = function(utftext) {
  415.             let string = "";
  416.             let i = 0;
  417.             let c = c1 = c2 = 0;
  418.            
  419.             while (i < utftext.length) {
  420.                 c = utftext.charCodeAt(i);
  421.                
  422.                 if (c < 128) {
  423.                     string += String.fromCharCode(c);
  424.                     i++;
  425.                 } else if ((c > 191) && (c < 224)) {
  426.                     c2 = utftext.charCodeAt(i + 1);
  427.                     string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
  428.                     i += 2;
  429.                 } else {
  430.                     c2 = utftext.charCodeAt(i + 1);
  431.                     c3 = utftext.charCodeAt(i + 2);
  432.                     string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
  433.                     i += 3;
  434.                 }
  435.             }
  436.            
  437.             return string;
  438.         };
  439.     },
  440.    
  441.     // 签名处理
  442.     sign: function(url) {
  443.         let base64 = new this.Base64();
  444.         url = this.customStrDecode(url);
  445.         let parts = url.split('/');
  446.         let result = '';
  447.        
  448.         for (let i = 0; i < parts.length; i++) {
  449.             let separator = (i + 1 == parts.length) ? '' : '/';
  450.             if (i == 0 || i == 1) {
  451.                 // 跳过前两部分
  452.             } else {
  453.                 result += parts[i] + separator;
  454.             }
  455.         }
  456.        
  457.         let signedData = base64.encode(result);
  458.         let finalUrl = this.deString(
  459.             JSON.parse(base64.decode(parts[1])),
  460.             JSON.parse(base64.decode(parts[0])),
  461.             signedData
  462.         );
  463.        
  464.         return finalUrl;
  465.     },
  466.    
  467.     // 检查值是否在数组中
  468.     indexOfVal: function(arr, val) {
  469.         for (let i = 0; i < arr.length; i++) {
  470.             if (val === arr[i]) return true;
  471.         }
  472.         return false;
  473.     },
  474.    
  475.     // 自定义字符串解码
  476.     customStrDecode: function(str) {
  477.         let base64 = new this.Base64();
  478.         key = md5("customKey");
  479.         str = base64.decode(str);
  480.         len = key.length;
  481.         code = '';
  482.        
  483.         for (i = 0; i < str.length; i++) {
  484.             k = i % len;
  485.             code += String.fromCharCode(str.charCodeAt(i) ^ key.charCodeAt(k));
  486.         }
  487.        
  488.         return base64.decode(code);
  489.     },
  490.    
  491.     // 字符串处理
  492.     deString: function(obj1, obj2, signedData) {
  493.         let result = '';
  494.         let keys1 = obj1;
  495.         let keys2 = obj2;
  496.         let chars = signedData.split('');
  497.        
  498.         for (let i = 0; i < chars.length; i++) {
  499.             let char = chars[i];
  500.             let isLetter = /^[a-zA-Z]+$/.test(char);
  501.            
  502.             if (isLetter && this.indexOfVal(keys2, char)) {
  503.                 result += keys2[keys1.indexOf(char)];
  504.             } else {
  505.                 result += char;
  506.             }
  507.         }
  508.        
  509.         return result;
  510.     }
  511. };
  512.  
  513. /**
  514.  * 解码器2 - 用于解码第二种类型的视频URL
  515.  */
  516. var Decode2 = {
  517.     get: function(url) {
  518.         return this.decode(url);
  519.     },
  520.    
  521.     // 解码方法
  522.     decode: function(str) {
  523.         str = atob(str);
  524.         let keyChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  525.         let result = '';
  526.        
  527.         for (let i = 1; i < str.length;) {
  528.             let index = keyChars.indexOf(str[i]);
  529.             if (index == -1) {
  530.                 var char = str[i];
  531.             } else {
  532.                 var char = keyChars[(index + 59) % 62];
  533.             }
  534.            
  535.             result += char;
  536.             i = i + 3;
  537.         }
  538.        
  539.         return result;
  540.     }
  541. };
Add Comment
Please, Sign In to add comment