├── .gitignore ├── assets ├── images │ ├── logo.png │ └── logo@2x.png ├── js │ ├── hermit-load.min.js │ ├── lib │ │ ├── jquery.mxloader.js │ │ ├── jquery.mxpage.js │ │ ├── jquery.mxlayer.js │ │ ├── hermit-load.js │ │ └── watch.js │ ├── hermit-load.js │ ├── blocks.build.js │ ├── hermit-post.js │ └── hermit-library.js └── css │ ├── hermit-post.css │ └── APlayer.min.css ├── README.md ├── include ├── cookies-pointer.php ├── template.php ├── library.php └── setting.php ├── LICENSE ├── hermit.php ├── hermit.functions.php ├── class.update.php ├── class.json.php └── class.hermit.php /.gitignore: -------------------------------------------------------------------------------- 1 | .history 2 | .vscode -------------------------------------------------------------------------------- /assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoePlayer/Hermit-X/HEAD/assets/images/logo.png -------------------------------------------------------------------------------- /assets/images/logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoePlayer/Hermit-X/HEAD/assets/images/logo@2x.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hermit-X 2 | 在 WordPress 中使用 APlayer 播放音乐吧~ 3 | 详细信息请访问[插件发布页](https://blog.lwl12.com/read/hermit-x.html)~ 4 | -------------------------------------------------------------------------------- /include/cookies-pointer.php: -------------------------------------------------------------------------------- 1 | Meting Wiki。'; 5 | ?> 6 | jQuery( function() { 7 | var pointer = jQuery( "#toplevel_page_hermit" ).pointer( { 8 | content: '

', 9 | pointerWidth: 300, 10 | 11 | position: { 12 | edge: "left", 13 | align: "center" 14 | }, 15 | 16 | close: function() { 17 | jQuery( window ).off( "scroll", reposition ); 18 | jQuery.get( "" ); 19 | } 20 | } ).pointer( "open" ), 21 | 22 | reposition = function() { 23 | pointer.pointer( "reposition" ); 24 | }; 25 | 26 | jQuery( window ).on( "scroll", reposition ); 27 | } ); 28 | prefix . 'hermit'; 40 | $hermit_cat_name = $wpdb->prefix . 'hermit_cat'; 41 | 42 | /** 43 | * 加载函数 44 | */ 45 | require HERMIT_PATH . '/hermit.functions.php'; 46 | 47 | /** 48 | * 插件激活,新建数据库 49 | */ 50 | register_activation_hook(__FILE__, 'hermit_install'); 51 | 52 | /** 53 | * 插件停用, 删除数据库 54 | */ 55 | //register_deactivation_hook(__FILE__, 'hermit_uninstall'); 56 | -------------------------------------------------------------------------------- /assets/js/hermit-load.min.js: -------------------------------------------------------------------------------- 1 | "use strict";var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a};function cloneObject(a){if(null==a||"object"!=("undefined"==typeof a?"undefined":_typeof(a)))return a;if(a instanceof Date){var b=new Date(a.getDate());return b}if(a instanceof Array){for(var b=[],c=0,d=a.length;cthis.status||304===this.status){var n=JSON.parse(this.responseText);if(m.music=n.msg.songs,void 0===m.music)return console.warn("Hermit-X failed to load "+d[l].songs),!1;void 0===m.showlrc&&(m.music[0].lrc?m.lrcType=3:m.lrcType=0),1===m.music.length&&(m.music=m.music[0]),m.autoplay&&(m.autoplay="true"===m.autoplay),m.listfolded&&(m.listFolded="true"===m.listfolded),m.mutex&&(m.mutex="true"===m.mutex),m.narrow&&(m.narrow="true"===m.narrow),ap[j]=new APlayer(m),ap[j].parseRespons=n,window.APlayerCall&&window.APlayerCall[j]&&window.APlayerCall[j](),window.APlayerloadAllCall&&a.length!=ap.length&&window.APlayerloadAllCall()}else console.error("Request was unsuccessful: "+this.status)};var k=HermitX.ajaxurl+"?action=hermit&musicset="+escape(d[j].songs)+"&_nonce="+d[j]._nonce;c[j].open("get",k,!0),c[j].send(null)}},g=0;gget_var("show tables like '{$hermit_table_name}'") != $hermit_table_name) { 10 | $wpdb->query("CREATE TABLE {$hermit_table_name} ( 11 | id INT(10) NOT NULL AUTO_INCREMENT, 12 | song_name VARCHAR(255) NOT NULL, 13 | song_author VARCHAR(255) NOT NULL, 14 | song_url TEXT NOT NULL, 15 | song_cover TEXT NOT NULL DEFAULT '', 16 | song_lrc LONGTEXT NOT NULL DEFAULT '', 17 | created DATETIME NOT NULL, 18 | UNIQUE KEY id (id) 19 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"); 20 | } 21 | 22 | if ($wpdb->get_var("show tables like '{$hermit_cat_name}'") != $hermit_cat_name) { 23 | $wpdb->query("CREATE TABLE {$hermit_cat_name} ( 24 | id INT(10) NOT NULL AUTO_INCREMENT, 25 | title VARCHAR(125) NOT NULL, 26 | UNIQUE KEY id (id) 27 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"); 28 | 29 | $wpdb->query("INSERT INTO `{$hermit_cat_name}` (`id`, `title`) VALUES (NULL, '未分类')"); 30 | $wpdb->query("ALTER TABLE `{$hermit_table_name}` ADD `song_cat` INT(3) NOT NULL DEFAULT '1' AFTER `song_author`"); 31 | } 32 | 33 | if (!$wpdb->get_results("SHOW COLUMNS FROM `{$hermit_table_name}` LIKE 'song_cover'")) { 34 | $wpdb->query("ALTER TABLE `{$hermit_table_name}` ADD `song_cover` TEXT NOT NULL DEFAULT '' AFTER `song_url`"); 35 | 36 | if (!$wpdb->query("show columns from `{$hermit_table_name}` like 'song_cover'")) { 37 | printf("请前往数据库 $hermit_table_name 手动添加 song_cover 字段"); 38 | die(); 39 | } 40 | } 41 | 42 | if (!$wpdb->get_results("SHOW COLUMNS FROM `{$hermit_table_name}` LIKE 'song_lrc'")) { 43 | $wpdb->query("ALTER TABLE `{$hermit_table_name}` ADD `song_lrc` LONGTEXT NOT NULL DEFAULT '' AFTER `song_cover`"); 44 | 45 | if (!$wpdb->query("show columns from `{$hermit_table_name}` like 'song_lrc'")) { 46 | printf("请前往数据库 $hermit_table_name 手动添加 song_lrc 字段"); 47 | die(); 48 | } 49 | } 50 | } 51 | 52 | function hermit_uninstall() 53 | { 54 | global $wpdb, $hermit_table_name, $hermit_cat_name; 55 | 56 | $wpdb->query("DROP TABLE IF EXISTS {$hermit_table_name}"); 57 | $wpdb->query("DROP TABLE IF EXISTS {$hermit_cat_name}"); 58 | } 59 | -------------------------------------------------------------------------------- /assets/js/lib/jquery.mxloader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name MXLoader.js 3 | * @version 0.0.1 4 | * @create 2015-09-16 5 | * @lastmodified 2015-09-16 17:36 6 | * @description jQuery loader plugin 7 | * @author MuFeng (http://mufeng.me) 8 | * @url http://mufeng.me 9 | **/ 10 | ;(function ($) { 11 | var MXLoader = function (element) { 12 | this.parent = element ? $(element) : $('body'); 13 | this.element = null; 14 | this.timer = null; 15 | 16 | this.init(); 17 | }; 18 | 19 | MXLoader.prototype = { 20 | init: function () { 21 | this.element = $('
'); 22 | this.parent.append(this.element); 23 | 24 | return this; 25 | }, 26 | 27 | show: function(type, message, after){//console.log('2.', after); 28 | clearTimeout(this.timer); 29 | this.timer = null; 30 | this.element.empty().show(); 31 | 32 | var $container = this.element; 33 | 34 | if(type=='progress'){ 35 | $container.append('
'+message+'
') 36 | $container.show(); 37 | after && after.call(this); 38 | }else{ 39 | $container.append('
'+message+'
'); 40 | 41 | var that = this; 42 | $container.show();//console.log('3.', after); 43 | that.timer = setTimeout(function(){//console.log('4.', after); 44 | that.dismiss(); 45 | after && after.call(that); 46 | }, 600); 47 | } 48 | }, 49 | 50 | showProgress: function(message){ 51 | this.show('progress', message); 52 | }, 53 | 54 | showSuccess: function(message, after){ 55 | //console.log('1.', after); 56 | this.show('success', message, after); 57 | }, 58 | 59 | showError: function(message, after){ 60 | this.show('error', message, after); 61 | }, 62 | 63 | showInfo: function(message, after){ 64 | this.show('info', message, after); 65 | }, 66 | 67 | dismiss: function () { 68 | var that = this; 69 | 70 | clearTimeout(that.timer); 71 | that.timer = null; 72 | that.element.hide().empty(); 73 | } 74 | }; 75 | 76 | $.mxloader = function (element) { 77 | return new MXLoader(element); 78 | }; 79 | })(jQuery); 80 | -------------------------------------------------------------------------------- /assets/js/lib/jquery.mxpage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name MXPage.js 3 | * @version 0.0.2 4 | * @create 2015-09-15 5 | * @lastmodified 2015-09-15 17:36 6 | * @description jQuery page navigation plugin 7 | * @author MuFeng (http://mufeng.me) 8 | * @url http://mufeng.me 9 | **/ 10 | ;(function ($) { 11 | var array, MXPage = function (x, y) { 12 | this.settings = x; 13 | this.element = $(y); 14 | 15 | this.layout(); 16 | }; 17 | 18 | MXPage.prototype = { 19 | layout: function () { 20 | if (this.settings.maxPage <= 1) return; 21 | 22 | this.fireEvent(); 23 | 24 | //最前页 25 | this.build(1, 'mxpage-front', this.settings.frontPageText); 26 | 27 | //上一页 28 | this.build(Math.max(1, this.settings.currentPage - 1), 'mxpage-previous', this.settings.previousText); 29 | 30 | //中间 31 | this.element.children('.pagination-links').append(' '+this.settings.currentPage+'/'+this.settings.maxPage+' '); 32 | 33 | //下一页 34 | this.build(Math.min(this.settings.maxPage, this.settings.currentPage + 1), 'mxpage-next', this.settings.nextText); 35 | 36 | //最后页 37 | this.build(this.settings.maxPage, 'mxpage-last', this.settings.lastPageText); 38 | 39 | //绑定点击事件 40 | this.addEvent(); 41 | }, 42 | 43 | build: function (index, className, title) { 44 | title = title || index; 45 | 46 | var html, 47 | that = this; 48 | 49 | if (className == 'mxpage-default' && this.settings.currentPage == index) { 50 | html = $('' + index + '') 51 | }else{ 52 | html = $('' + title + '') 53 | } 54 | 55 | that.element.children('.pagination-links').append(html); 56 | }, 57 | 58 | addEvent: function () { 59 | var that = this; 60 | 61 | that.element.on('click', '.mxpage', function (event) { 62 | var $this = $(this), 63 | index = parseInt($this.attr('data-page')); 64 | 65 | if (that.settings.currentPage == index) return; 66 | 67 | that.settings.currentPage = index; 68 | that.layout(); 69 | 70 | //回调 71 | that.settings.click(index, $this); 72 | }); 73 | }, 74 | 75 | fireEvent: function () { 76 | if (this.element.children('.pagination-links')) { 77 | this.element.children('.pagination-links').remove(); 78 | this.element.off('click'); 79 | } 80 | 81 | this.element.append(''); 82 | } 83 | }; 84 | 85 | $.mxpage = function (x, y) { 86 | //参数合并 87 | x = $.extend({ 88 | perPage: 10, 89 | currentPage: 1, 90 | maxPage: 1, 91 | previousText: 'previous', 92 | nextText: 'next', 93 | frontPageText: 'front page', 94 | lastPageText: 'last page', 95 | click: function (index, $element) {} 96 | }, x); 97 | 98 | $.data(y, 'mxpage', new MXPage(x, y)); 99 | 100 | return y; 101 | }; 102 | 103 | $.fn.mxpage = function (x) { 104 | return $.mxpage(x, this); 105 | }; 106 | })(jQuery); -------------------------------------------------------------------------------- /assets/css/hermit-post.css: -------------------------------------------------------------------------------- 1 | /** 2 | * @name Hermit 3 | * @version 1.9.3 4 | * @create 2014-02-07 5 | * @lastmodified 2015-10-06 14:32 6 | * @description Hermit Plugin 7 | * @author MuFeng (http://mufeng.me) 8 | * @url http://mufeng.me/hermit-for-wordpress.html 9 | **/ 10 | .clearfix:after,.clearfix:before{content:"";display:table;clear:both;overflow:hidden}body.hermit-hidden{overflow:hidden}.wp-media-buttons img{display:inline-block;margin-top:-4px}#hermit-remote-content ul li:after,#hermit-remote-content ul li:before{background:#0073aa;width:1px;position:absolute;height:0;content:""}#hermit-shell{position:relative}#hermit-shell .media-frame-content,#hermit-shell .media-frame-router,#hermit-shell .media-frame-title,#hermit-shell .media-frame-toolbar{left:0}#hermit-shell .media-router{padding-left:16px;padding-right:16px}#hermit-shell .media-frame-content{padding:20px;overflow:hidden}#hermit-shell .hermit-li{display:none}#hermit-shell .hermit-li.active{display:block}#hermit-shell .media-frame-content label{padding-right:10px}#hermit-shell .media-router a,#hermit-shell .media-router a:active,#hermit-shell .media-router a:foucs{outline:0}#hermit-shell .hermit-ul{display:block;height:200px;overflow:hidden}#hermit-shell-content{height:500px;width:800px;left:50%;top:50%;margin-left:-400px;margin-top:-250px;right:auto;bottom:auto}.media-router a:focus{box-shadow:none}#hermit-preview.texted{padding:5px;margin-top:10px;background:#f1f1f1;color:#000;word-wrap:break-word}#hermit-preview,.hermit-textarea{font-size:13px;font-family:Consolas,Monaco,monospace}#hermit-shell textarea.large-text{width:98.2%;margin-top:10px}#hermit-remote-content{height:198px;overflow-x:hidden;overflow-y:auto}#hermit-remote-content ul{display:block}#hermit-remote-content ul li{display:inline-block;padding:0 50px 0 10px;background:#fff;width:120px;border:1px solid #ddd;position:relative;cursor:pointer;height:30px;line-height:30px;overflow:hidden}.hermit-help{float:right;padding:5px 20px 0 0}#hermit-remote-content ul li:before{right:20px;top:12px;transform:rotate(-45deg);-ms-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-webkit-transform:rotate(-45deg);-o-transform:rotate(-45deg)}#hermit-remote-content ul li.selected:before{-webkit-animation:selected .15s linear forwards;-moz-animation:selected .15s linear forwards;-ms-animation:selected .15s linear forwards;-o-animation:selected .15s linear forwards;animation:selected .15s linear forwards}#hermit-remote-content ul li:after{right:13px;top:17px;transform:rotate(30deg);-ms-transform:rotate(30deg);-moz-transform:rotate(30deg);-webkit-transform:rotate(30deg);-o-transform:rotate(30deg)}#hermit-remote-content ul li.selected:after{-webkit-animation:selected2 .3s linear alternate forwards;-moz-animation:selected2 .3s linear forwards;-ms-animation:selected2 .3s linear forwards;-o-animation:selected2 .3s linear forwards;animation:selected2 .3s linear forwards}.hermit-remote-footer{padding:10px 0;text-align:center}#hermit-remote-button{display:inline-block;font-size:12px}@-webkit-keyframes selected{100%,50%{height:10px}}@-moz-keyframes selected{100%,50%{height:10px}}@-ms-keyframes selected{100%,50%{height:10px}}@-o-keyframes selected{100%,50%{height:10px}}@keyframes selected{100%,50%{height:10px}}@-webkit-keyframes selected2{0%,49%{height:0;top:17px}100%{height:16px;top:5px}}@-moz-keyframes selected2{0%,49%{height:0;top:17px}100%{height:16px;top:5px}}@-ms-keyframes selected2{0%,49%{height:0;top:17px}100%{height:16px;top:5px}}@-o-keyframes selected2{0%,49%{height:0;top:17px}100%{height:16px;top:5px}}@keyframes selected2{0%,49%{height:0;top:17px}100%{height:16px;top:5px}}#hermit-shell-close{text-align:center;line-height:50px}#hermit-shell-close .media-modal-icon{vertical-align:middle;display:inline-block}@media screen and (max-width:767px){#hermit-shell-content{width:100%;height:100%;margin-left:0;margin-top:0;top:0;left:0}} -------------------------------------------------------------------------------- /assets/js/lib/jquery.mxlayer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name MXLayer.js 3 | * @version 0.0.1 4 | * @create 2015-09-15 5 | * @lastmodified 2015-09-15 17:36 6 | * @description jQuery popup layer plugin 7 | * @author MuFeng (http://mufeng.me) 8 | * @url http://mufeng.me 9 | **/ 10 | ;(function ($) { 11 | var MXLayer = function (x) { 12 | this.settings = x; //console.log(this.settings); 13 | this.layout(); 14 | }; 15 | 16 | MXLayer.prototype = { 17 | layout: function () { 18 | var $element = $(this.html()); 19 | $('body').append($element); 20 | 21 | this.element = $element; 22 | 23 | if(this.settings.sidebar){ 24 | this.element.addClass('sidebar'); 25 | this.element.find('.mxlayer-sidebar-body').html(this.settings.sidebar) 26 | } 27 | 28 | this.element.find('.mxlayer-main-header h1').text(this.settings.title); 29 | this.element.find('.mxlayer-confirm-button').text(this.settings.button); 30 | this.element.find('.mxlayer-main-body').html(this.settings.main); 31 | 32 | if(this.settings.width && this.settings.height){ 33 | this.element.find('.mxlayer-content').css({ 34 | width: this.settings.width, 35 | height: this.settings.height, 36 | left: '50%', 37 | top: '50%', 38 | marginLeft: -this.settings.width/2, 39 | marginTop: -this.settings.height/2 40 | }) 41 | } 42 | 43 | this.addEvent(); 44 | }, 45 | 46 | addEvent: function(){ 47 | var that = this, 48 | closeElement = that.element.find('.mxlayer-close'), 49 | confirmElement = that.element.find('.mxlayer-confirm-button'); 50 | 51 | closeElement.on('click', function(event){ 52 | console.log($(this)); 53 | that.fireEvent(); 54 | 55 | that.settings.cancel.call(null, that) 56 | }); 57 | 58 | confirmElement.on('click', function(event){ 59 | that.settings.confirm.call(null, that) 60 | }); 61 | }, 62 | 63 | fireEvent: function() 64 | { 65 | var closeElement = this.element.find('.mxlayer-close'), 66 | confirmElement = this.element.find('.mxlayer-confirm-button'); 67 | 68 | closeElement.off('click'); 69 | confirmElement.off('click'); 70 | this.element.remove(); 71 | this.element = null; 72 | }, 73 | 74 | html: function(){ 75 | return '
\ 76 |
\ 77 |
\ 78 |
\ 79 |
\ 80 |
\ 81 |

\ 82 | \ 83 |
\ 84 |
\ 85 | \ 88 |
\ 89 |
\ 90 |
\ 91 |
' 92 | } 93 | }; 94 | 95 | $.mxlayer = function (x) { 96 | //参数合并 97 | x = $.extend({ 98 | title: 'Title', 99 | sidebar: false, 100 | main: false, 101 | button: 'Confirm', 102 | width: 0, 103 | height: 0, 104 | cancel: function(){}, 105 | confirm: function(){} 106 | }, x); 107 | 108 | return new MXLayer(x) 109 | }; 110 | })(jQuery); 111 | -------------------------------------------------------------------------------- /assets/js/hermit-load.js: -------------------------------------------------------------------------------- 1 | function cloneObject(src) { 2 | if (src == null || typeof src != "object") { 3 | return src; 4 | } 5 | if (src instanceof Date) { 6 | var clone = new Date(src.getDate()); 7 | return clone; 8 | } 9 | if (src instanceof Array) { 10 | var clone = []; 11 | for (var i = 0, len = src.length; i < len; i++) { 12 | clone[i] = src[i]; 13 | } 14 | return clone; 15 | } 16 | if (src instanceof Object) { 17 | var clone = {}; 18 | for (var key in src) { 19 | if (src.hasOwnProperty(key)) { 20 | clone[key] = cloneObject(src[key]); 21 | } 22 | } 23 | return clone; 24 | } 25 | } 26 | 27 | function hermitInit() { 28 | var aps = document.getElementsByClassName("aplayer"); 29 | var apnum = 0; 30 | ap = []; 31 | var xhr = []; 32 | var option = []; 33 | for (let i = 0; i < aps.length; i++) { 34 | if (aps[i].dataset.songs) { 35 | option[i] = cloneObject(aps[i].dataset); 36 | option[i].element = aps[i]; 37 | xhr[i] = new XMLHttpRequest(); 38 | xhr[i].onreadystatechange = function() { 39 | var index = xhr.indexOf(this); 40 | var op = option[index]; 41 | op.storageName = "HxAP-Setting"; 42 | if (this.readyState === 4) { 43 | if (this.status >= 200 && this.status < 300 || this.status === 304) { 44 | var response = JSON.parse(this.responseText); 45 | op.music = response.msg.songs; 46 | if (op.music === undefined) { 47 | console.warn("Hermit-X failed to load " + option[index].songs); 48 | return false; 49 | } 50 | if (op.showlrc === undefined) { 51 | if (op.music[0].lrc) { 52 | op.lrcType = 3; 53 | } else { 54 | op.lrcType = 0; 55 | } 56 | } 57 | if (op.music.length === 1) { 58 | op.music = op.music[0]; 59 | } 60 | if (op.autoplay) { 61 | op.autoplay = (op.autoplay === "true"); 62 | } 63 | if (op.listfolded) { 64 | op.listFolded = (op.listfolded === "true"); 65 | } 66 | if (op.mutex) { 67 | op.mutex = (op.mutex === "true"); 68 | } 69 | if (op.narrow) { 70 | op.narrow = (op.narrow === "true"); 71 | } 72 | ap[i] = new APlayer(op); 73 | ap[i].parseRespons = response; 74 | if (window.APlayerCall && window.APlayerCall[i]) window.APlayerCall[i](); 75 | if (window.APlayerloadAllCall && aps.length != ap.length) { 76 | window.APlayerloadAllCall(); 77 | } 78 | } else { 79 | console.error("Request was unsuccessful: " + this.status); 80 | } 81 | } 82 | }; 83 | const apiurl = HermitX.ajaxurl + "?action=hermit&musicset=" + escape(option[i].songs) + "&_nonce=" + option[i]._nonce; 84 | xhr[i].open("get", apiurl, true); 85 | xhr[i].send(null); 86 | } 87 | } 88 | } 89 | 90 | function reloadHermit() { 91 | for (var i = 0; i < ap.length; i++) { 92 | try { 93 | ap[i].destroy(); 94 | } catch (e) {} 95 | } 96 | hermitInit(); 97 | } 98 | var ap = []; 99 | document.addEventListener("DOMContentLoaded", reloadHermit); 100 | console.log("\n %c Hermit X Music Helper v" + HermitX.version + " %c https://lwl.moe/HermitX \n", "color: #fff; background: #4285f4; padding:5px 0;", "background: #66CCFF; padding:5px 0;"); 101 | -------------------------------------------------------------------------------- /assets/js/lib/hermit-load.js: -------------------------------------------------------------------------------- 1 | function cloneObject(src) { 2 | if (src == null || typeof src != "object") { 3 | return src 4 | } 5 | if (src instanceof Date) { 6 | var clone = new Date(src.getDate()); 7 | return clone 8 | } 9 | if (src instanceof Array) { 10 | var clone = []; 11 | for (var i = 0, len = src.length; i < len; i++) { 12 | clone[i] = src[i] 13 | } 14 | return clone 15 | } 16 | if (src instanceof Object) { 17 | var clone = {}; 18 | for (var key in src) { 19 | if (src.hasOwnProperty(key)) { 20 | clone[key] = cloneObject(src[key]) 21 | } 22 | } 23 | return clone 24 | } 25 | } 26 | 27 | function hermitInit() { 28 | var aps = document.getElementsByClassName("aplayer"); 29 | var apnum = 0; 30 | ap = []; 31 | if (HermitX.sat == "1"){ 32 | var setTheme = []; 33 | } 34 | var xhr = []; 35 | var option = []; 36 | for (var i = 0; i < aps.length; i++) { 37 | if (aps[i].dataset.songs) { 38 | option[i] = cloneObject(aps[i].dataset); 39 | option[i].element = aps[i]; 40 | xhr[i] = new XMLHttpRequest(); 41 | xhr[i].onreadystatechange = function() { 42 | var index = xhr.indexOf(this); 43 | var op = option[index]; 44 | op.storageName = "HxAP-Setting"; 45 | if (this.readyState === 4) { 46 | if (this.status >= 200 && this.status < 300 || this.status === 304) { 47 | var response = JSON.parse(this.responseText); 48 | op.music = response.msg.songs; 49 | if (op.music === undefined) { 50 | console.warn("Hermit-X failed to load " + option[index].songs); 51 | return false; 52 | } 53 | if (op.music.length === 1) { 54 | op.music = op.music[0]; 55 | } 56 | if (op.autoplay) { 57 | op.autoplay = (op.autoplay === "true"); 58 | } 59 | if (op.listfolded) { 60 | op.listFolded = (op.listfolded === "true"); 61 | } 62 | if (op.mutex) { 63 | op.mutex = (op.mutex === "true"); 64 | } 65 | if (op.narrow) { 66 | op.narrow = (op.narrow === "true"); 67 | } 68 | ap[i] = new APlayer(op); 69 | ap[i].parseRespons = response; 70 | if (window.APlayerCall && window.APlayerCall[i]) window.APlayerCall[i](); 71 | if (window.APlayerloadAllCall && aps.length != ap.length) { 72 | window.APlayerloadAllCall(); 73 | } 74 | if (HermitX.sat == "1") { 75 | setTheme[i] = (index) => { 76 | if (!ap[i].list.audios[index].theme) { 77 | const colorThief = new ColorThief(); 78 | colorThief.getColorAsync(ap[i].list.audios[index].cover, function (color) { 79 | ap[i].theme(`rgb(${color[0]}, ${color[1]}, ${color[2]})`, index); 80 | }); 81 | } 82 | }; 83 | setTheme[i](ap[i].list.index); 84 | ap[i].on('listswitch', (data) => { 85 | setTheme[i](data.index); 86 | }); 87 | } 88 | } else { 89 | console.error("Request was unsuccessful: " + this.status); 90 | } 91 | } 92 | }; 93 | var scope = option[i].songs.split("#:"); 94 | apiurl = HermitX.ajaxurl + "?action=hermit&scope=" + option[i].songs.split("#:")[0] + "&id=" + option[i].songs.split("#:")[1] + "&_nonce=" + option[i]._nonce; 95 | xhr[i].open("get", apiurl, true); 96 | xhr[i].send(null); 97 | } 98 | } 99 | } 100 | 101 | function reloadHermit() { 102 | for (var i = 0; i < ap.length; i++) { 103 | try { 104 | ap[i].destroy() 105 | } catch (e) {} 106 | } 107 | hermitInit() 108 | } 109 | hermitInit(); 110 | console.log(`\n %c Hermit X Music Helper v` + HermitX.version + ` %c https://lwl.moe/HermitX \n`, `color: #fff; background: #4285f4; padding:5px 0;`, `background: #66CCFF; padding:5px 0;`); 111 | -------------------------------------------------------------------------------- /assets/js/blocks.build.js: -------------------------------------------------------------------------------- 1 | !function(e){function t(l){if(a[l])return a[l].exports;var n=a[l]={i:l,l:!1,exports:{}};return e[l].call(n.exports,n,n.exports,t),n.l=!0,n.exports}var a={};t.m=e,t.c=a,t.d=function(e,a,l){t.o(e,a)||Object.defineProperty(e,a,{configurable:!1,enumerable:!0,get:l})},t.n=function(e){var a=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(a,"a",a),a},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=0)}([function(e,t,a){"use strict";Object.defineProperty(t,"__esModule",{value:!0});a(1)},function(e,t,a){"use strict";var l=a(2),n=(a.n(l),a(3)),i=(a.n(n),a(4)),o=(a.n(i),wp.i18n.__),r=wp.blocks,s=r.registerBlockType,c=(r.query,function(e,t){var a="";switch(e){case"xiami_songlist":(t=t.match(/(http|https):\/\/(www.)?xiami.com\/song\//gi))&&0 2 |
3 |
4 |
5 | 关闭媒体面板 7 | 8 |
9 |
10 |

插入音乐

11 |
12 |
13 | 21 |
22 |
23 |
    24 |
  • 25 |
    26 | 27 | 28 | 29 |
    30 | 32 |
  • 33 |
  • 34 |
    35 | 36 | 37 | 38 |
    39 | 41 |
  • 42 |
  • 43 |
    44 | 45 | 46 | 47 |
    48 | 50 |
  • 51 |
  • 52 |
    53 | 54 | 55 | 56 |
    57 | 61 |
  • 62 |
  • 63 |
    64 | 65 | 66 | 67 |
    68 | 70 |
  • 71 |
  • 72 |
    73 |
      74 | 77 |
      78 |
    • 79 |
    80 |
    81 | 82 | 88 | 93 |
    94 |
    95 |
    96 |
    97 |
    98 |
    99 |
    100 | 插入至文章 103 |
    104 |
    105 |
    106 |
    107 |
    108 |
    109 |
    110 |
    111 |
    112 | 113 | 118 | -------------------------------------------------------------------------------- /assets/js/lib/watch.js: -------------------------------------------------------------------------------- 1 | "use strict";(function(t){"object"===typeof exports?module.exports=t():"function"===typeof define&&define.amd?define(t):(window.WatchJS=t(),window.watch=window.WatchJS.watch,window.unwatch=window.WatchJS.unwatch,window.callWatchers=window.WatchJS.callWatchers)})(function(){function t(){u=null;for(var a=0;amusic_catList(); 3 | $prePage = $this->settings('prePage'); 4 | $count = $this->music_count(); 5 | $maxPage = ceil($count / $prePage); 6 | $catid = isset($_GET['catid']) && $_GET['catid'] ? $_GET['catid'] : null; 7 | ?> 8 |
    9 |

    Hermit X 音乐库 新建音乐

    10 | 11 |
    12 |
      13 |
      14 |
      15 | 16 | 21 | 22 |
      23 |
      24 |
      25 |
      26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
      40 | 41 | 42 | 封面歌曲名称作者分类地址歌词操作
      57 | 58 | 59 | 封面歌曲名称作者分类地址歌词操作
      70 |
      71 |
      72 | 73 | 78 | 79 |
      80 |
      81 |
      82 |
      83 |
      84 | 85 | 86 | 132 | 133 | 134 | 138 | 139 | 140 | 143 | 144 | 145 | 162 | 163 | 164 | 165 | 171 | 172 | 173 | 185 | 186 | 187 | 213 | 214 | 225 |
      -------------------------------------------------------------------------------- /include/setting.php: -------------------------------------------------------------------------------- 1 |
      2 |

      Hermit X 插件设置

      3 |

      设置已保存。

      '; 5 | } ?> 6 |
      7 | 8 | 9 | 10 | 11 | 12 | 36 | 37 | 38 | 39 | 62 | 63 | 64 | 65 | 94 | 95 | 96 | 97 | 103 | 104 | 105 | 106 | 127 | 128 | 129 | 130 | 139 | 140 | 141 | 142 | 148 | 149 | 150 | 151 | 157 | 158 | 159 | 160 | 174 | 175 | 176 | 177 | 187 | 188 | 189 | 190 | 202 | 203 | 204 | 205 | 208 | 209 | 210 |
      13 |

      14 | 21 |

      22 | 23 |

      24 | 31 |

      32 | 33 |

      默认:按需加载,只有文章列表中使用了短代码才会加载CSS、JS资源。
      全局加载:无论是否使用了短代码都会加载,适合侧边栏。 34 |

      35 |
      40 |

      41 | 48 |

      49 | 50 |

      51 | 58 |

      59 | 60 |

      默认:页面顶部

      61 |
      66 | '默认', 68 | 'red' => '新年红', 69 | 'blue' => '青葱绿', 70 | 'yellow' => '淡淡黄', 71 | 'pink' => '少女粉', 72 | 'purple' => '基情紫', 73 | 'black' => '暗色灰', 74 | 'customize' => '自定义' 75 | ); 76 | foreach ($color_array as $key => $title) { 77 | ?> 78 | 89 | 93 |
      98 |

      100 | 101 |

      默认数量:20。

      102 |
      107 | '极高 (320kbit/s)', 109 | '192' => '较高 (192kbit/s)', 110 | '128' => '普通 (128kbit/s)', 111 | ); 112 | foreach ($quality_array as $key => $title) { 113 | ?> 114 | 121 | 125 |

      实际音质小于等于所选音质。默认极高

      126 |
      131 |

      136 | 137 |

      默认使用 Nonce 验证保证 Hermit X 音乐信息接口不被恶意利用。
      仅在您需要使用全页面缓存等无法兼容 nonce 验证的情况下需要启用该选项。开启该选项会显著降低接口安全性

      138 |
      143 |

      145 | 146 |

      Hermit X 将使用此代理服务器请求各曲源服务器。

      147 |
      152 |

      154 | 155 |

      如需播放网易云音乐付费歌曲类特殊曲目,请将有权限的网易云音乐帐号(如 VIP 帐号)COOKIES 填入,建议使用手机 APP COOKIES。
      如您不理解该选项有何意义或是如何使用,请忽略。

      156 |
      161 |

      166 | 167 |

      是否默认折叠播放列表

      168 |
      169 |

      列表最大高度 px

      171 | 172 |

      限制播放列表的最大高度,0为不限制。

      173 |
      178 | 179 |

      184 | 185 |

      在前台使用 jsDelivr 加载 JS、CSS 等资源文件,提升访问速度。

      186 |
      191 | $details) { 192 | ?> 193 | 198 | 200 |

      默认:管理员权限 才可以在新建或编辑文章时添加音乐

      201 |
      206 | 207 |
      211 |
      212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /assets/css/APlayer.min.css: -------------------------------------------------------------------------------- 1 | .aplayer{background:#fff;font-family:Arial,Helvetica,sans-serif;margin:5px;box-shadow:0 2px 2px 0 rgba(0,0,0,.07),0 1px 5px 0 rgba(0,0,0,.1);border-radius:2px;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;line-height:normal;position:relative}.aplayer *{box-sizing:content-box}.aplayer svg{width:100%;height:100%}.aplayer svg circle,.aplayer svg path{fill:#fff}.aplayer.aplayer-withlist .aplayer-info{border-bottom:1px solid #e9e9e9}.aplayer.aplayer-withlist .aplayer-list{display:block}.aplayer.aplayer-withlist .aplayer-icon-order,.aplayer.aplayer-withlist .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon.aplayer-icon-menu{display:inline}.aplayer.aplayer-withlrc .aplayer-pic{height:90px;width:90px}.aplayer.aplayer-withlrc .aplayer-info{margin-left:90px;height:90px;padding:10px 7px 0}.aplayer.aplayer-withlrc .aplayer-lrc{display:block}.aplayer.aplayer-narrow{width:66px}.aplayer.aplayer-narrow .aplayer-info,.aplayer.aplayer-narrow .aplayer-list{display:none}.aplayer.aplayer-narrow .aplayer-body,.aplayer.aplayer-narrow .aplayer-pic{height:66px;width:66px}.aplayer.aplayer-fixed{position:fixed;bottom:0;left:0;right:0;margin:0;z-index:99;overflow:visible;max-width:400px;box-shadow:none}.aplayer.aplayer-fixed .aplayer-list{margin-bottom:65px;border:1px solid #eee;border-bottom:none}.aplayer.aplayer-fixed .aplayer-body{position:fixed;bottom:0;left:0;right:0;margin:0;z-index:99;background:#fff;padding-right:18px;transition:all .3s ease;max-width:400px}.aplayer.aplayer-fixed .aplayer-lrc{display:block;position:fixed;bottom:10px;left:0;right:0;margin:0;z-index:98;pointer-events:none;text-shadow:-1px -1px 0 #fff}.aplayer.aplayer-fixed .aplayer-lrc:after,.aplayer.aplayer-fixed .aplayer-lrc:before{display:none}.aplayer.aplayer-fixed .aplayer-info{-webkit-transform:scaleX(1);transform:scaleX(1);-webkit-transform-origin:0 0;transform-origin:0 0;transition:all .3s ease;border-bottom:none;border-top:1px solid #e9e9e9}.aplayer.aplayer-fixed .aplayer-info .aplayer-music{width:calc(100% - 105px)}.aplayer.aplayer-fixed .aplayer-miniswitcher{display:block}.aplayer.aplayer-fixed.aplayer-narrow .aplayer-info{display:block;-webkit-transform:scaleX(0);transform:scaleX(0)}.aplayer.aplayer-fixed.aplayer-narrow .aplayer-body{width:66px!important}.aplayer.aplayer-fixed.aplayer-narrow .aplayer-miniswitcher .aplayer-icon{-webkit-transform:rotateY(0);transform:rotateY(0)}.aplayer.aplayer-fixed .aplayer-icon-back,.aplayer.aplayer-fixed .aplayer-icon-forward,.aplayer.aplayer-fixed .aplayer-icon-lrc,.aplayer.aplayer-fixed .aplayer-icon-play{display:inline-block}.aplayer.aplayer-fixed .aplayer-icon-back,.aplayer.aplayer-fixed .aplayer-icon-forward,.aplayer.aplayer-fixed .aplayer-icon-menu,.aplayer.aplayer-fixed .aplayer-icon-play{position:absolute;bottom:27px;width:20px;height:20px}.aplayer.aplayer-fixed .aplayer-icon-back{right:75px}.aplayer.aplayer-fixed .aplayer-icon-play{right:50px}.aplayer.aplayer-fixed .aplayer-icon-forward{right:25px}.aplayer.aplayer-fixed .aplayer-icon-menu{right:0}.aplayer.aplayer-arrow .aplayer-icon-loop,.aplayer.aplayer-arrow .aplayer-icon-order,.aplayer.aplayer-mobile .aplayer-icon-volume-down{display:none}.aplayer.aplayer-loading .aplayer-info .aplayer-controller .aplayer-loading-icon{display:block}.aplayer.aplayer-loading .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played .aplayer-thumb{-webkit-transform:scale(1);transform:scale(1)}.aplayer .aplayer-body{position:relative}.aplayer .aplayer-icon{width:15px;height:15px;border:none;background-color:transparent;outline:none;cursor:pointer;opacity:.8;vertical-align:middle;padding:0;font-size:12px;margin:0;display:inline-block}.aplayer .aplayer-icon path{transition:all .2s ease-in-out}.aplayer .aplayer-icon-back,.aplayer .aplayer-icon-forward,.aplayer .aplayer-icon-lrc,.aplayer .aplayer-icon-order,.aplayer .aplayer-icon-play{display:none}.aplayer .aplayer-icon-lrc-inactivity svg{opacity:.4}.aplayer .aplayer-icon-forward{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.aplayer .aplayer-lrc-content{display:none}.aplayer .aplayer-pic{position:relative;float:left;height:66px;width:66px;background-size:cover;background-position:50%;transition:all .3s ease;cursor:pointer}.aplayer .aplayer-pic:hover .aplayer-button{opacity:1}.aplayer .aplayer-pic .aplayer-button{position:absolute;border-radius:50%;opacity:.8;text-shadow:0 1px 1px rgba(0,0,0,.2);box-shadow:0 1px 1px rgba(0,0,0,.2);background:rgba(0,0,0,.2);transition:all .1s ease}.aplayer .aplayer-pic .aplayer-button path{fill:#fff}.aplayer .aplayer-pic .aplayer-hide{display:none}.aplayer .aplayer-pic .aplayer-play{width:26px;height:26px;border:2px solid #fff;bottom:50%;right:50%;margin:0 -15px -15px 0}.aplayer .aplayer-pic .aplayer-play svg{position:absolute;top:3px;left:4px;height:20px;width:20px}.aplayer .aplayer-pic .aplayer-pause{width:16px;height:16px;border:2px solid #fff;bottom:4px;right:4px}.aplayer .aplayer-pic .aplayer-pause svg{position:absolute;top:2px;left:2px;height:12px;width:12px}.aplayer .aplayer-info{margin-left:66px;padding:14px 7px 0 10px;height:66px;box-sizing:border-box}.aplayer .aplayer-info .aplayer-music{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;margin:0 0 13px 5px;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;cursor:default;padding-bottom:2px;height:20px}.aplayer .aplayer-info .aplayer-music .aplayer-title{font-size:14px}.aplayer .aplayer-info .aplayer-music .aplayer-author{font-size:12px;color:#666}.aplayer .aplayer-info .aplayer-controller{position:relative;display:flex}.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap{margin:0 0 0 5px;padding:4px 0;cursor:pointer!important;flex:1}.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap:hover .aplayer-bar .aplayer-played .aplayer-thumb{-webkit-transform:scale(1);transform:scale(1)}.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar{position:relative;height:2px;width:100%;background:#cdcdcd}.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-loaded{position:absolute;left:0;top:0;bottom:0;background:#aaa;height:2px;transition:all .5s ease}.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played{position:absolute;left:0;top:0;bottom:0;height:2px}.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played .aplayer-thumb{position:absolute;top:0;right:5px;margin-top:-4px;margin-right:-10px;height:10px;width:10px;border-radius:50%;cursor:pointer;transition:all .3s ease-in-out;-webkit-transform:scale(0);transform:scale(0)}.aplayer .aplayer-info .aplayer-controller .aplayer-time{position:relative;right:0;bottom:4px;height:17px;color:#999;font-size:11px;padding-left:7px}.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-time-inner{vertical-align:middle}.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon{cursor:pointer;transition:all .2s ease}.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon path{fill:#666}.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon.aplayer-icon-loop{margin-right:2px}.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon:hover path{fill:#000}.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon.aplayer-icon-menu,.aplayer .aplayer-info .aplayer-controller .aplayer-time.aplayer-time-narrow .aplayer-icon-menu,.aplayer .aplayer-info .aplayer-controller .aplayer-time.aplayer-time-narrow .aplayer-icon-mode{display:none}.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap{position:relative;display:inline-block;margin-left:3px;cursor:pointer!important}.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap:hover .aplayer-volume-bar-wrap{height:40px}.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap{position:absolute;bottom:15px;right:-3px;width:25px;height:0;z-index:99;overflow:hidden;transition:all .2s ease-in-out}.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap.aplayer-volume-bar-wrap-active{height:40px}.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap .aplayer-volume-bar{position:absolute;bottom:0;right:10px;width:5px;height:35px;background:#aaa;border-radius:2.5px;overflow:hidden}.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap .aplayer-volume-bar .aplayer-volume{position:absolute;bottom:0;right:0;width:5px;transition:all .1s ease}.aplayer .aplayer-info .aplayer-controller .aplayer-loading-icon{display:none}.aplayer .aplayer-info .aplayer-controller .aplayer-loading-icon svg{position:absolute;-webkit-animation:rotate 1s linear infinite;animation:rotate 1s linear infinite}.aplayer .aplayer-lrc{display:none;position:relative;height:30px;text-align:center;overflow:hidden;margin:-10px 0 7px}.aplayer .aplayer-lrc:before{top:0;height:10%;background:linear-gradient(180deg,#fff 0,hsla(0,0%,100%,0));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ffffff",endColorstr="#00ffffff",GradientType=0)}.aplayer .aplayer-lrc:after,.aplayer .aplayer-lrc:before{position:absolute;z-index:1;display:block;overflow:hidden;width:100%;content:" "}.aplayer .aplayer-lrc:after{bottom:0;height:33%;background:linear-gradient(180deg,hsla(0,0%,100%,0) 0,hsla(0,0%,100%,.8));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#00ffffff",endColorstr="#ccffffff",GradientType=0)}.aplayer .aplayer-lrc p{font-size:12px;color:#666;line-height:16px!important;height:16px!important;padding:0!important;margin:0!important;transition:all .5s ease-out;opacity:.4;overflow:hidden}.aplayer .aplayer-lrc p.aplayer-lrc-current{opacity:1;overflow:visible;height:auto!important;min-height:16px}.aplayer .aplayer-lrc.aplayer-lrc-hide{display:none}.aplayer .aplayer-lrc .aplayer-lrc-contents{width:100%;transition:all .5s ease-out;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;cursor:default}.aplayer .aplayer-list{overflow:auto;transition:all .5s ease;will-change:height;display:none;overflow:hidden}.aplayer .aplayer-list.aplayer-list-hide{max-height:0!important}.aplayer .aplayer-list ol{list-style-type:none;margin:0;padding:0;overflow-y:auto}.aplayer .aplayer-list ol::-webkit-scrollbar{width:5px}.aplayer .aplayer-list ol::-webkit-scrollbar-thumb{border-radius:3px;background-color:#eee}.aplayer .aplayer-list ol::-webkit-scrollbar-thumb:hover{background-color:#ccc}.aplayer .aplayer-list ol li{position:relative;height:32px;line-height:32px;padding:0 15px;font-size:12px;border-top:1px solid #e9e9e9;cursor:pointer;transition:all .2s ease;overflow:hidden;margin:0}.aplayer .aplayer-list ol li:first-child{border-top:none}.aplayer .aplayer-list ol li:hover{background:#efefef}.aplayer .aplayer-list ol li.aplayer-list-light{background:#e9e9e9}.aplayer .aplayer-list ol li.aplayer-list-light .aplayer-list-cur{display:inline-block}.aplayer .aplayer-list ol li .aplayer-list-cur{display:none;width:3px;height:22px;position:absolute;left:0;top:5px;cursor:pointer}.aplayer .aplayer-list ol li .aplayer-list-index{color:#666;margin-right:12px;cursor:pointer}.aplayer .aplayer-list ol li .aplayer-list-author{color:#666;float:right;cursor:pointer}.aplayer .aplayer-notice{opacity:0;position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);font-size:12px;border-radius:4px;padding:5px 10px;transition:all .3s ease-in-out;overflow:hidden;color:#fff;pointer-events:none;background-color:#f4f4f5;color:#909399}.aplayer .aplayer-miniswitcher{display:none;position:absolute;top:0;right:0;bottom:0;height:100%;background:#e6e6e6;width:18px;border-radius:0 2px 2px 0}.aplayer .aplayer-miniswitcher .aplayer-icon{height:100%;width:100%;-webkit-transform:rotateY(180deg);transform:rotateY(180deg);transition:all .3s ease}.aplayer .aplayer-miniswitcher .aplayer-icon path{fill:#666}.aplayer .aplayer-miniswitcher .aplayer-icon:hover path{fill:#000}@-webkit-keyframes aplayer-roll{0%{left:0}to{left:-100%}}@keyframes aplayer-roll{0%{left:0}to{left:-100%}}@-webkit-keyframes rotate{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotate{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}} 2 | 3 | /*# sourceMappingURL=APlayer.min.css.map*/ -------------------------------------------------------------------------------- /class.update.php: -------------------------------------------------------------------------------- 1 | last_checked ) ) { 85 | unset( $update->last_checked ); 86 | set_site_transient( 'update_plugins', $update ); 87 | } 88 | 89 | wp_update_plugins(); 90 | } 91 | 92 | /** 93 | * 输出版本控制工具使用警告 94 | * 95 | * @since Hermit X 2.5.9 96 | */ 97 | public function vcs_warning() { 98 | if ( !current_user_can( 'activate_plugins' ) ) 99 | return; 100 | 101 | $dismissed = get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ); 102 | $dismissed = array_filter( explode( ',', (string) $dismissed ) ); 103 | 104 | if ( in_array( 'hermit-vcs-warning', $dismissed ) ) 105 | return; 106 | 107 | if ( !$this->is_vcs_checkout() ) { 108 | /* $dismissed[] = 'hermit-vcs-warning'; 109 | $dismissed = implode( ',', $dismissed ); 110 | 111 | update_user_meta( 112 | get_current_user_id(), 113 | 'dismissed_wp_pointers', 114 | $dismissed 115 | ); 116 | */ 117 | return; 118 | } 119 | 120 | $text = '警告:使用版本控制系统可能导致 Hermit X 更新失败'; 121 | $text .= ',请删除本插件目录下的 .git 文件夹或其他版本控制文件(夹)。'; 122 | 123 | echo ' 124 |
      125 |

      ' . $text . '

      126 |
      127 | '; 135 | } 136 | 137 | /** 138 | * 启动更新通知程序 139 | * 140 | * @since Hermit X 2.6.3 141 | */ 142 | public function setup_notify_email( $upgrader, $hook_extra ) { 143 | if ( $hook_extra['action'] != 'update' ) 144 | return; 145 | 146 | if ( $hook_extra['type'] != 'plugin' ) 147 | return; 148 | 149 | if ( empty( $hook_extra['bulk'] ) ) { 150 | if ( $hook_extra['plugin'] != $this->get_plugin_file() ) return; 151 | } else { 152 | if ( !in_array( $this->get_plugin_file(), $hook_extra['plugins'] ) ) return; 153 | } 154 | 155 | $args = array( $this->get_plugin_version() ); 156 | wp_schedule_single_event( time(), 'hermit_maybe_notify_email', $args ); 157 | } 158 | 159 | /** 160 | * 检测条件并发送更新通知 161 | * 162 | * @since Hermit X 2.6.3 163 | */ 164 | public function maybe_notify_email( $version ) { 165 | if ( ( $data = $this->get_update_data() ) && !empty( $data->notify_email ) ) 166 | $this->notify_email( $version ); 167 | } 168 | 169 | /** 170 | * 插入插件更新信息 171 | * 172 | * @since Hermit X 2.5.9 173 | * @since Hermit X 2.6.3 会从 `self::get_update_data()` 方法的返回值中筛选出版本信息。 174 | */ 175 | public function insert_update_data( $update ) { 176 | if (($data = $this->get_update_data()) && !empty($data->response) ) { 177 | $file = $this->get_plugin_file(); 178 | $update->response[$file] = $data->response; 179 | } 180 | 181 | return $update; 182 | } 183 | 184 | /** 185 | * 重命名软件包 186 | * 187 | * @since Hermit X 2.5.9 188 | */ 189 | public function rename_package( $source, $remote_source, $upgrader, $hook_extra ) { 190 | if ( empty( $hook_extra['plugin'] ) ) 191 | return $source; 192 | 193 | if ( $hook_extra['plugin'] != $this->get_plugin_file() ) 194 | return $source; 195 | 196 | global $wp_filesystem; 197 | $filename = dirname( $source ) . '/' . dirname( $this->get_plugin_file() ); 198 | 199 | if ( !$wp_filesystem->move( $source, $filename, true ) ) 200 | return new WP_Error( 'rename_failed', 'Rename Failed.' ); 201 | 202 | return $filename; 203 | } 204 | 205 | /** 206 | * 从远程服务器获取插件更新数据 207 | * 208 | * @since Hermit X 2.5.9 209 | * @since Hermit X 2.6.0 新增 TTL 的支持;修复启用插件时 HTTP 请求次数过多的问题。 210 | * @since Hermit X 2.6.3 返回 API 传送的所有内容,而不仅仅是版本信息。 211 | */ 212 | private function get_update_data() { 213 | if ( isset( $this->update_data ) ) 214 | return $this->update_data; 215 | 216 | $wp_version = get_bloginfo( 'version' ); 217 | $home_url = home_url(); 218 | 219 | $response = wp_remote_post( $this->api, array( 220 | 'timeout' => 10, 221 | 'user-agent' => "WordPress/{$wp_version}; {$home_url}", 222 | 223 | 'body' => array( 224 | 'url' => $home_url, 225 | 'blogname' => get_option('blogname'), 226 | 'admin_email' => get_option('admin_email'), 227 | 'file' => $this->get_plugin_file(), 228 | 'version' => $this->get_plugin_version(), 229 | 'wp_version' => $wp_version, 230 | 'php_version' => phpversion(), 231 | 'wp_locale' => get_locale() 232 | ) 233 | ) ); 234 | 235 | if ( wp_remote_retrieve_response_code( $response ) == 200 ) { 236 | $body = wp_remote_retrieve_body( $response ); 237 | $body = json_decode( trim( $body ) ); 238 | 239 | if ( $body && is_object( $body ) ) { 240 | if ( !empty( $body->response->autoupdate ) ) 241 | wp_schedule_single_event( time() + 10, 'wp_version_check' ); 242 | 243 | if ( !empty( $body->ttl ) ) { 244 | $ttl = (int) $body->ttl; 245 | $ttl += time(); 246 | 247 | if ( $ttl < wp_next_scheduled( 'wp_version_check' ) ) 248 | wp_schedule_single_event( $ttl, 'wp_version_check' ); 249 | } 250 | 251 | $this->update_data = $body; 252 | } else { 253 | $this->update_data = false; 254 | } 255 | } 256 | 257 | return $this->update_data; 258 | } 259 | 260 | /** 261 | * 发送更新通知 262 | * 263 | * @since Hermit X 2.6.3 264 | */ 265 | private function notify_email( $version ) { 266 | $message_plain = "尊敬的 ".get_option('blogname')." 站长,您好!您站点的 Hermit X 插件已成功更新至".$version."版本!".PHP_EOL."您可以在 Github 查看有关此次更新的详细信息".PHP_EOL."https://github.com/liwanglin12/Hermit-X/commits/master".PHP_EOL."此致 ".PHP_EOL."Hermit X 开发团队敬上".PHP_EOL.PHP_EOL."此电子邮件地址无法接收回复。如需更多信息,请前往 Github 或插件发布页查询."; 267 | $message_plain = strip_tags($message_plain); 268 | //HTML Version 269 | $message_html = '
      270 | 271 |
      LWL Labs wrench
      您站点的 Hermit X 已成功更新
      274 |
      273 |
      尊敬的 '.get_option('blogname').' 站长,您好!
      您站点的 Hermit X 插件已成功更新至'.$version.'版本。*uniqueID* 272 |

      '.($version==="2.7.0" ? "此次更新为重要更新," : "").'您可以在 Github 查看有关此次更新的详细信息*uniqueID*
      此致
      Hermit X 开发团队敬上*uniqueID*
      此电子邮件地址无法接收回复。如需更多信息,请前往 插件发布页 或 Github 查询。*uniqueID*
      我们向您发送这封电子邮件通知,目的是让您了解与您站点相关的变化。
      © '.date('Y').' LWL的自由天空, Hermit X Developer Team
      '; 275 | //Handle HTML Message. 1.Convert smilies 2.Generation random code 3.Replace *uniqueID* mark to random code to fix Gmail issue. 276 | $message_html = str_replace("*uniqueID*", substr(md5(uniqid() . microtime()), 0, 5), convert_smilies($message_html)); 277 | //Set mail headers 278 | $subject = '您站点 ['.get_option('blogname').'] 的 Hermit X 插件已成功更新<( ̄v ̄)/'; 279 | //Hook phpmailer init action, then force change message_type to alt. 280 | global $phpmailer; 281 | add_action('phpmailer_init', function (&$phpmailer) use ($message_html, $message_plain){ 282 | $phpmailer->isHTML(true); 283 | $phpmailer->Body = $message_html; 284 | $phpmailer->AltBody = $message_plain; 285 | $phpmailer->CharSet = 'utf-8'; 286 | $phpmailer->Encoding = 'base64'; 287 | $phpmailer->MessageID = '<' . md5($message_plain.microtime().uniqid()).'@hermit.x.update>'; 288 | }); 289 | wp_mail(get_option('blogname')." <".get_option('admin_email').">", $subject, $message_html); 290 | } 291 | 292 | /** 293 | * 获取插件文件名 294 | * 295 | * @since Hermit X 2.5.9 296 | */ 297 | private function get_plugin_file() { 298 | return plugin_basename( HERMIT_FILE ); 299 | } 300 | 301 | /** 302 | * 获取插件版本 303 | * 304 | * @since Hermit X 2.5.9 305 | */ 306 | private function get_plugin_version() { 307 | if ( !function_exists( 'get_plugin_data' ) ) 308 | require_once( ABSPATH . 'wp-admin/includes/plugin.php' ); 309 | 310 | $plugin = get_plugin_data( HERMIT_FILE ); 311 | return $plugin['Version']; 312 | } 313 | 314 | /** 315 | * 检测插件目录是否使用了版本控制工具 316 | * 317 | * @since Hermit X 2.5.9 318 | * @since Hermit X 2.6.0 使用插件目录替换原来的 `WP_PLUGIN_DIR`。 319 | */ 320 | private function is_vcs_checkout() { 321 | include_once( ABSPATH . '/wp-admin/includes/admin.php' ); 322 | include_once( ABSPATH . '/wp-admin/includes/class-wp-upgrader.php' ); 323 | 324 | $upgrader = new WP_Automatic_Updater; 325 | return $upgrader->is_vcs_checkout( HERMIT_PATH ); 326 | } 327 | 328 | } 329 | 330 | // End of page. 331 | -------------------------------------------------------------------------------- /assets/js/hermit-post.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name Hermit X 3 | * @version 1.9.4 4 | * @create 2014-02-07 5 | * @lastmodified 2017-01-14 21:00 6 | * @description Hermit X Plugin 7 | * @author MuFeng (http://mufeng.me), liwanglin12 (https://lwl12.com) 8 | * @url http://mufeng.me/hermit-for-wordpress.html 9 | **/ 10 | jQuery(document).ready(function(b) { 11 | function n(c, a) { 12 | if (d.array = "", "xiami" == c) { 13 | switch (d.type) { 14 | case "xiami_songlist": 15 | (a = a.match(/(http|https):\/\/(www.)?xiami.com\/song\//gi)) && 0 < a.length && (d.array = "Wating Parse..."); 16 | break; 17 | case "xiami_album": 18 | (a = a.match(/(http|https):\/\/(www.)?xiami.com\/album\//gi)) && 0 < a.length && (d.array = "Wating Parse..."); 19 | break; 20 | case "xiami_playlist": 21 | (a = a.match(/(http|https):\/\/(www.)?xiami.com\/collect\//gi)) && 0 < a.length && (d.array = "Wating Parse..."); 22 | break 23 | } 24 | } 25 | if ("netease" == c) { 26 | switch (d.type) { 27 | case "netease_songlist": 28 | (a = a.match(/(song\?id=(\d+)|\/song\/(\d+))/gi)) && 0 < a.length && (es = [], b.each(a, 29 | function(a, c) { 30 | -1 === b.inArray(c, e) && es.push(c) 31 | }), d.array = es.join(",").replace(/(song\?id=|\/song\/)/gi, "")); 32 | break; 33 | case "netease_songs": 34 | (a = a.match(/song\?id=(\d+)/gi)) && 0 < a.length && (e = [], b.each(a, 35 | function(a, c) { 36 | - 1 === b.inArray(c, e) && e.push(c) 37 | }), d.array = e.join(",").replace(/song\?id=/g, "")); 38 | break; 39 | case "netease_album": 40 | (a = a.match(/(album\?id=(\d+)|\/album\/(\d+))/i)) && 0 < a.length && (d.array = a[0].replace(/(album\?id=|\/album\/)/gi, "")); 41 | break; 42 | case "netease_playlist": 43 | (a = a.match(/(playlist\?id=(\d+)|\/playlist\/(\d+))/i)) && 0 < a.length && (d.array = a[0].replace(/(playlist\?id=|\/playlist\/)/gi, "")) 44 | } 45 | } 46 | 47 | if ("tencent" == c) { 48 | switch (d.type) { 49 | case "tencent_songlist": 50 | (a = a.match(/y\.qq\.com\/n\/yqq\/song\/([A-Za-z0-9]+)/gi)) && 0 < a.length && (e = [], b.each(a, 51 | function(a, c) { 52 | - 1 === b.inArray(c, e) && e.push(c) 53 | }), d.array = e.join(",").replace(/y\.qq\.com\/n\/yqq\/song\//gi, "")); 54 | break; 55 | case "tencent_album": 56 | (a = a.match(/y\.qq\.com\/n\/yqq\/album\/([A-Za-z0-9]+)/i)) && 0 < a.length && (d.array = a[0].replace(/y\.qq\.com\/n\/yqq\/album\//gi, "")); 57 | break; 58 | case "tencent_playlist": 59 | (a = a.match(/y\.qq\.com\/n\/yqq\/playlist\/(\d+)/i)) && 0 < a.length && (d.array = a[0].replace(/y\.qq\.com\/n\/yqq\/playlist\//gi, "")) 60 | } 61 | } 62 | if ("kugou" == c) { 63 | switch (d.type) { 64 | case "kugou_songlist": 65 | (a = a.match(/[A-Za-z0-9]+/gi)) && 0 < a.length && (es = [], b.each(a, 66 | function(a, c) { 67 | -1 === b.inArray(c, e) && es.push(c) 68 | }), d.array = es.join(",")); 69 | break; 70 | case "kugou_album": 71 | (a = a.match(/[A-Za-z0-9]+/i)) && 0 < a.length && (d.array = a[0]); 72 | break; 73 | case "kugou_playlist": 74 | (a = a.match(/[A-Za-z0-9]+/i)) && 0 < a.length && (d.array = a[0]); 75 | } 76 | } 77 | if ("baidu" == c) { 78 | switch (d.type) { 79 | case "baidu_songlist": 80 | (a = a.match(/music\.taihe\.com\/song\/\d+/gi)) && 0 < a.length && (es = [], b.each(a, 81 | function(a, c) { 82 | -1 === b.inArray(c, e) && es.push(c) 83 | }), d.array = es.join(",").replace(/music\.taihe\.com\/song\//gi, "")); 84 | break; 85 | case "baidu_album": 86 | (a = a.match(/music\.taihe\.com\/album\/\d+/i)) && 0 < a.length && (d.array = a[0].replace(/music\.taihe\.com\/album\//gi, "")); 87 | break; 88 | case "baidu_playlist": 89 | (a = a.match(/music\.taihe\.com\/songlist\/\d+/i)) && 0 < a.length && (d.array = a[0].replace(/music\.taihe\.com\/songlist\//gi, "")) 90 | } 91 | } 92 | "remote" == c && (d.type = "remote", d.array = a); 93 | d.array ? b("#hermit-shell-insert").removeAttr("disabled") : b("#hermit-shell-insert").attr("disabled", "disabled"); 94 | k(c, d) 95 | } 96 | 97 | function k(c, a) { 98 | l = '[hermit autoplay="' + (a.auto ? 'true' : 'false') + '" mode="' + a.mode + '" preload="' + a.preload +'"]' + a.type + "#:" + a.array + "[/hermit]"; 99 | b("#hermit-preview").text(l).addClass("texted") 100 | } 101 | void 0 === window.send_to_editor && (window.send_to_editor = function(b) { 102 | var a, d = "undefined" != typeof tinymce, 103 | e = "undefined" != typeof QTags; 104 | if (wpActiveEditor) { 105 | d && (a = tinymce.get(wpActiveEditor)) 106 | } else { 107 | if (d && tinymce.activeEditor) { 108 | a = tinymce.activeEditor, 109 | wpActiveEditor = a.id 110 | } else { 111 | if (!e) { 112 | return !1 113 | } 114 | } 115 | } 116 | if (a && !a.isHidden() ? a.execCommand("mceInsertContent", !1, b) : e ? QTags.insertContent(b) : document.getElementById(wpActiveEditor).value += b, window.tb_remove) { 117 | try { 118 | window.tb_remove() 119 | } catch (f) {} 120 | } 121 | }); 122 | var f, l, h, r = b("#hermit-create"), 123 | e = b("body"), 124 | p = b("#hermit-template").html(), 125 | t = Handlebars.compile(p), 126 | p = b("#hermit-remote-template").html(), 127 | q = Handlebars.compile(p), 128 | d = { 129 | type: "", 130 | array: "", 131 | auto: 0, 132 | loop: 0, 133 | unexpand: 0, 134 | fullheight: 0 135 | }, 136 | m = 1, 137 | g = !1; 138 | r.length ? r.click(function() { 139 | f = "netease"; 140 | d = { 141 | type: "", 142 | array: "", 143 | auto: 0, 144 | loop: 0, 145 | unexpand: 0, 146 | fullheight: 0 147 | }; 148 | l = ""; 149 | e.append(t()); 150 | d.mode = 'circulation'; 151 | d.preload = 'auto'; 152 | b("body").addClass("hermit-hidden") 153 | }) : 1 == hermit.roles.length && "contributor" == hermit.roles[0] && (b("#wp-content-editor-tools").prepend(''), b("#wp-content-editor-tools").on("click", "#hermit-create", 154 | function() { 155 | f = "netease"; 156 | d = { 157 | type: "", 158 | array: "", 159 | auto: 0, 160 | loop: 0, 161 | unexpand: 0, 162 | fullheight: 0 163 | }; 164 | l = ""; 165 | e.append(t()); 166 | b("body").addClass("hermit-hidden") 167 | })); 168 | e.on("click", "#hermit-shell-close", 169 | function() { 170 | b("#hermit-shell").remove(); 171 | b("body").removeClass("hermit-hidden") 172 | }); 173 | e.on("click", "#hermit-shell-insert", 174 | function() { 175 | if (f == "xiami") { 176 | id_parse('xiami'); 177 | // } else if (d.type == "tencent_songlist") { 178 | // id_parse('tencent'); 179 | } else { 180 | "disabled" != b(this).attr("disabled") && (send_to_editor(l.replace(/,+$/g, "")), b("#hermit-shell").remove()); 181 | b("body").removeClass("hermit-hidden") 182 | } 183 | }); 184 | function id_parse(site) { 185 | switch (site) { 186 | case 'xiami': 187 | b("#hermit-shell-insert").text( "Xiami Music ID Parsing..."); 188 | break; 189 | // case 'tencent': 190 | // b("#hermit-shell-insert").text("Tencent Music ID Parsing..."); 191 | } 192 | b.ajax({ 193 | url: hermit.ajax_url, 194 | data: { 195 | action: "hermit", 196 | scope: site + "_id_parse", 197 | src: b(".hermit-li.active .hermit-textarea").val().replace(/\n/g, ","), 198 | }, 199 | success: function(c) { 200 | b("#hermit-shell-insert").text("插入至文章"); 201 | "disabled" != b(this).attr("disabled") && (send_to_editor(l.replace("Wating Parse...", c.msg.join(",").replace(/,+$/g, ""))), b("#hermit-shell").remove()); 202 | b("body").removeClass("hermit-hidden") 203 | }, 204 | error: function() { 205 | b("#hermit-shell-insert").text("插入至文章"); 206 | alert("\u83b7\u53d6\u5931\u8d25, \u8bf7\u7a0d\u5019\u91cd\u8bd5") 207 | } 208 | }) 209 | } 210 | e.on("click", "#hermit-remote-content ul li", 211 | function() { 212 | var c = b(this), 213 | a = []; 214 | c.hasClass("selected") ? c.removeClass("selected") : c.addClass("selected"); 215 | b("#hermit-remote-content ul li.selected").each(function() { 216 | a.push(b(this).attr("data-id")) 217 | }); 218 | a = a.join(","); 219 | n(f, a) 220 | }); 221 | e.on("click", ".media-router a", 222 | function() { 223 | var c = b(this), 224 | a = b(".media-router a").index(c); 225 | c.hasClass("active") || (b(".media-router a.active,.hermit-li.active").removeClass("active"), c.addClass("active"), b(".hermit-li").eq(a).addClass("active"), f = b(".hermit-li").eq(a).attr("data-type"), "remote" == f && (h ? b("#hermit-remote-content ul").html(q(h)) : b.ajax({ 226 | url: hermit.ajax_url, 227 | data: { 228 | action: "hermit_source", 229 | type: "list", 230 | paged: 1 231 | }, 232 | beforeSend: function() { 233 | g = !0 234 | }, 235 | success: function(a) { 236 | g = !1; 237 | h = a; 238 | b("#hermit-remote-content ul").html(q(h)); 239 | b("#hermit-remote-button").text("\u52a0\u8f7d\u66f4\u591a (1/" + hermit.max_page + ")").show() 240 | }, 241 | error: function() { 242 | m = 0; 243 | g = !1; 244 | b("#hermit-remote-button").text("\u52a0\u8f7d\u66f4\u591a (0/" + hermit.max_page + ")").show(); 245 | alert("\u83b7\u53d6\u5931\u8d25, \u8bf7\u7a0d\u5019\u91cd\u8bd5") 246 | } 247 | }))) 248 | }); 249 | e.on("click", "#hermit-auto", 250 | function() { 251 | var c = b(this); 252 | d.auto = c.prop("checked") ? 1 : 0; 253 | k(f, d) 254 | }); 255 | e.on("change", "#hermit-mode", 256 | function() { 257 | var c = b(this); 258 | d.mode = c.val(); 259 | k(f, d) 260 | }); 261 | e.on("change", "#hermit-preload", 262 | function() { 263 | var c = b(this); 264 | d.preload = c.val(); 265 | k(f, d) 266 | }); 267 | e.on("change", ".hermit-li.active input", 268 | function() { 269 | var c = b(".hermit-li.active .hermit-textarea").val(); 270 | d.type = b(".hermit-li.active input:checked").val(); 271 | n(f, c) 272 | }); 273 | e.on("focus keyup input paste", ".hermit-textarea", 274 | function() { 275 | var c = b(this).val(); 276 | d.type = b(".hermit-li.active input:checked").val(); 277 | n(f, c) 278 | }); 279 | e.on("click", "#hermit-remote-button", 280 | function() { 281 | g || (m >= hermit.max_page ? b(this).text("\u5df2\u662f\u6700\u540e\u4e00\u9875").fadeOut(1500, 282 | function() { 283 | b(this).hide() 284 | }) : (g = !0, b(this).addClass("loading").text("\u52a0\u8f7d\u4e2d..."), b.ajax({ 285 | url: hermit.ajax_url, 286 | data: { 287 | action: "hermit_source", 288 | type: "list", 289 | paged: m + 1 290 | }, 291 | success: function(c) { 292 | h.data = h.data.concat(c.data); 293 | b("#hermit-remote-content ul").append(q(c)); 294 | m++; 295 | b("#hermit-remote-button").text("\u52a0\u8f7d\u66f4\u591a (" + m + "/" + hermit.max_page + ")"); 296 | g = !1 297 | }, 298 | error: function() { 299 | alert("\u83b7\u53d6\u5931\u8d25, \u8bf7\u7a0d\u5019\u91cd\u8bd5"); 300 | g = !1 301 | } 302 | }))) 303 | }) 304 | }); 305 | -------------------------------------------------------------------------------- /class.json.php: -------------------------------------------------------------------------------- 1 | _settings = get_option('hermit_setting'); 13 | require('include/Meting.php'); 14 | } 15 | 16 | public function song_url($site, $music_id) 17 | { 18 | $cacheKey = "/$site/song_url/$music_id"; 19 | $url = $this->get_cache($cacheKey); 20 | if ($url) { 21 | Header("X-Hermit-Cached: From Cache"); 22 | Header("Location: " . $url); 23 | exit; 24 | } 25 | $Meting = new \Metowolf\Meting($site); 26 | 27 | $cookies = $this->settings('netease_cookies'); 28 | if (!empty($cookies) && $site === "netease") $Meting->cookie($cookies); 29 | 30 | $proxy = $this->settings('proxy'); 31 | if (!empty($proxy)) $Meting->proxy($proxy); 32 | 33 | $url = json_decode($Meting->format()->url($music_id, $this->settings('quality')), true); 34 | $url = $url['url']; 35 | 36 | // if (empty($url)) { 37 | // Header("Location: " . 'https://api.lwl12.com/music/netease/song?id=607441'); 38 | // exit; 39 | // } 40 | 41 | if ($site == 'netease') { 42 | $url = str_replace('://m7c.', '://m7.', $url); 43 | $url = str_replace('://m8c.', '://m8.', $url); 44 | $url = str_replace('http://', 'https://', $url); 45 | } 46 | if ($site == 'tencent') { 47 | $url = str_replace('http://', 'https://', $url); 48 | $url = str_replace('ws.stream.qqmusic.qq.com', 'dl.stream.qqmusic.qq.com', $url); 49 | } 50 | if ($site == 'xiami') { 51 | $url = str_replace('http://', 'https://', $url); 52 | } 53 | if ($site == 'baidu') { 54 | $url = str_replace('http://zhangmenshiting.qianqian.com', 'https://gss3.baidu.com/y0s1hSulBw92lNKgpU_Z2jR7b2w6buu', $url); 55 | } 56 | 57 | $this->set_cache($cacheKey, $url, 0.25); 58 | Header("Location: " . $url); 59 | exit; 60 | } 61 | 62 | private function pic_url($site, $id, $pic) 63 | { 64 | $cacheKey = "/$site/pic_url/$pic"; 65 | $url = $this->get_cache($cacheKey); 66 | if (!empty($url)) return $url; 67 | 68 | $Meting = new \Metowolf\Meting($site); 69 | $proxy = $this->settings('proxy'); 70 | if (!empty($proxy)) $Meting->proxy($proxy); 71 | $cookies = $this->settings('netease_cookies'); 72 | if (!empty($cookies) && $site === "netease") $Meting->cookie($cookies); 73 | 74 | $pic = json_decode($Meting->pic($pic, ($site === 'tencent') ? 90 : 100), true); 75 | if (empty($pic["url"])) { 76 | return null; 77 | } 78 | if ($site === 'netease' || $site === "xiami" || $site === 'tencent') { 79 | $pic['url'] = str_replace('http://', 'https://', $pic['url']); 80 | } 81 | $this->set_cache($cacheKey, $pic["url"], 168); 82 | return $pic["url"]; 83 | } 84 | 85 | public function lyric($site, $id) 86 | { 87 | $cacheKey = "/$site/lyric/$id"; 88 | $value = $this->get_cache($cacheKey); 89 | if ($value) { 90 | Header("X-Hermit-Cached: From Cache"); 91 | return $value; 92 | } 93 | $Meting = new \Metowolf\Meting($site); 94 | $proxy = $this->settings('proxy'); 95 | if (!empty($proxy)) $Meting->proxy($proxy); 96 | $cookies = $this->settings('netease_cookies'); 97 | if (!empty($cookies) && $site === "netease") $Meting->cookie($cookies); 98 | 99 | $value = json_decode($Meting->format(true)->lyric($id), true); 100 | $value = $this->lrctran($value['lyric'],$value['tlyric']); 101 | if (empty($value)) { 102 | $value = "[00:00.000]此歌曲暂无歌词,请您欣赏"; 103 | } 104 | 105 | if ($site === 'tencent') { 106 | $value = html_entity_decode($value, ENT_QUOTES | ENT_HTML5); 107 | } 108 | 109 | $this->set_cache($cacheKey, $value, 24); 110 | return $value; 111 | } 112 | 113 | private function lrctrim($lyrics) 114 | { 115 | $result = ""; 116 | $lyrics = explode("\n", $lyrics); 117 | $data = array(); 118 | foreach($lyrics as $key => $lyric){ 119 | preg_match('/\[(\d{2}):(\d{2}[\.:]?\d*)]/', $lyric, $lrcTimes); 120 | $lrcText = preg_replace('/\[(\d{2}):(\d{2}[\.:]?\d*)]/', '', $lyric); 121 | if (empty($lrcTimes)) { 122 | continue; 123 | } 124 | $lrcTimes = intval($lrcTimes[1]) * 60000 + intval(floatval($lrcTimes[2]) * 1000); 125 | $lrcText = preg_replace('/\s\s+/', ' ', $lrcText); 126 | $lrcText = trim($lrcText); 127 | $data[] = array($lrcTimes, $key, $lrcText); 128 | } 129 | sort($data); 130 | return $data; 131 | } 132 | 133 | private function lrctran($lyric,$tlyric) 134 | { 135 | $lyric = $this->lrctrim($lyric); 136 | $tlyric = $this->lrctrim($tlyric); 137 | $len1 = count($lyric); 138 | $len2 = count($tlyric); 139 | $result = ""; 140 | for($i=0,$j=0; $i<$len1&&$j<$len2; $i++){ 141 | while ($lyric[$i][0]>$tlyric[$j][0]&&$j+1<$len2) { 142 | $j++; 143 | } 144 | if ($lyric[$i][0] == $tlyric[$j][0]) { 145 | $tlyric[$j][2] = str_replace('/', '', $tlyric[$j][2]); 146 | if(!empty($tlyric[$j][2])){ 147 | $lyric[$i][2] .= " ({$tlyric[$j][2]})"; 148 | } 149 | $j++; 150 | } 151 | } 152 | for($i=0; $i<$len1; $i++){ 153 | $t = $lyric[$i][0]; 154 | $result .= sprintf("[%02d:%02d.%03d]%s\n", $t/60000, $t%60000/1000, $t%1000, $lyric[$i][2]); 155 | } 156 | return $result; 157 | } 158 | 159 | public function id_parse($site, $src) 160 | { 161 | foreach ($src as $key => $value) { 162 | $cacheKey = "/$site/idparse/$value"; 163 | $cache = $this->get_cache($cacheKey); 164 | if ($cache) { 165 | $ids[] = $cache; 166 | continue; 167 | } 168 | 169 | switch ($site) { 170 | // case 'tencent': 171 | // $request = array( 172 | // 'url' => $value, 173 | // 'referer' => 'https://y.qq.com/portal/player.html', 174 | // 'cookie' => 'pgv_pvi=3832878080; pgv_si=s4066364416; pgv_pvid=3938077488; yplayer_open=1; qqmusic_fromtag=66; ts_last=y.qq.com/portal/player.html; ts_uid=5141451452; player_exist=1; yq_index=1', 175 | // 'useragent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36', 176 | // ); 177 | // break; 178 | 179 | case 'xiami': 180 | $request = array( 181 | 'url' => $value, 182 | 'referer' => 'http://h.xiami.com/', 183 | 'cookie' => 'user_from=2;XMPLAYER_addSongsToggler=0;XMPLAYER_isOpen=0;_xiamitoken=c7c00f36f7f1acc679c3ad4ee5aabebd;', 184 | 'useragent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36', 185 | ); 186 | break; 187 | } 188 | $response = $this->curl($request); 189 | switch ($site) { 190 | case 'xiami': 191 | $re = '//'; 192 | break; 193 | // case 'tencent': 194 | // $re = '/g_SongData.*"songmid":"(?[A-Za-z0-9]+)".*"songtype"/'; 195 | // break; 196 | default: 197 | return false; 198 | break; 199 | } 200 | 201 | preg_match($re, $response, $matches); 202 | $ids[] = $matches['id']; 203 | $this->set_cache($cacheKey, $matches['id'], 744); 204 | } 205 | return $ids; 206 | } 207 | 208 | public function song($site, $music_id) 209 | { 210 | $Meting = new \Metowolf\Meting($site); 211 | $cache_key = "/$site/song/$music_id"; 212 | 213 | $cache = $this->get_cache($cache_key); 214 | if ($cache) { 215 | return $this->addNonce($cache, $site, true); 216 | } 217 | 218 | $cookies = $this->settings('netease_cookies'); 219 | if (!empty($cookies) && $site === "netease") $Meting->cookie($cookies); 220 | 221 | $proxy = $this->settings('proxy'); 222 | if (!empty($proxy)) $Meting->proxy($proxy); 223 | 224 | $response = json_decode($Meting->format()->song($music_id), true); 225 | 226 | if (!empty($response[0]["id"])) { 227 | //处理音乐信息 228 | $mp3_url = admin_url() . "admin-ajax.php" . "?action=hermit&scope=" . $site . "_song_url&id=" . $response[0]['url_id']; 229 | $music_name = $response[0]['name']; 230 | $cover = $this->pic_url($site, $music_id, $response[0]['pic_id']); 231 | $lyric = admin_url() . "admin-ajax.php" . "?action=hermit&scope=" . $site . "_lyric&id=" . $response[0]['lyric_id']; 232 | $artists = $response[0]['artist']; 233 | $artists = implode(",", $artists); 234 | 235 | $result = array( 236 | "id" => $response[0]["id"], 237 | "title" => $music_name, 238 | "author" => $artists, 239 | "url" => $mp3_url, 240 | "pic" => $cover, 241 | "lrc" => $lyric 242 | ); 243 | 244 | $this->set_cache($cache_key, $result, 23); 245 | 246 | return $this->addNonce($result, $site, true); 247 | } 248 | 249 | return false; 250 | } 251 | 252 | public function songlist($site, $song_list) 253 | { 254 | if (!$song_list) { 255 | return false; 256 | } 257 | 258 | $songs_array = explode(",", $song_list); 259 | $songs_array = array_unique($songs_array); 260 | 261 | if (!empty($songs_array)) { 262 | $result = array(); 263 | foreach ($songs_array as $song_id) { 264 | $result['songs'][] = $this->song($site, $song_id); 265 | } 266 | return $result; 267 | } 268 | 269 | return false; 270 | } 271 | 272 | public function album($site, $album_id) 273 | { 274 | $Meting = new \Metowolf\Meting($site); 275 | $cache_key = "/$site/album/$album_id"; 276 | 277 | $cache = $this->get_cache($cache_key); 278 | if ($cache) { 279 | return $this->addNonce($cache, $site); 280 | } 281 | 282 | $proxy = $this->settings('proxy'); 283 | if (!empty($proxy)) $Meting->proxy($proxy); 284 | 285 | $cookies = $this->settings('netease_cookies'); 286 | if (!empty($cookies) && $site === "netease") $Meting->cookie($cookies); 287 | 288 | $response = json_decode($Meting->format()->album($album_id), true); 289 | 290 | if (!empty($response[0])) { 291 | //处理音乐信息 292 | $result = $response; 293 | $count = count($result); 294 | 295 | if ($count < 1) { 296 | return false; 297 | } 298 | 299 | $album = array( 300 | "album_id" => $album_id, 301 | "album_type" => "albums", 302 | "album_count" => $count 303 | ); 304 | 305 | 306 | foreach ($result as $k => $value) { 307 | $mp3_url = admin_url() . "admin-ajax.php" . "?action=hermit&scope=" . $site . "_song_url&id=" . $value["url_id"]; 308 | $cover = $this->pic_url($site, $value['id'], $value['pic_id']); 309 | $lyric = admin_url() . "admin-ajax.php" . "?action=hermit&scope=" . $site . "_lyric&id=" . $value['lyric_id']; 310 | $album["songs"][] = array( 311 | "id" => $value["id"], 312 | "title" => $value["name"], 313 | "url" => $mp3_url, 314 | "author" => $album_author = implode(",", $value['artist']), 315 | "pic" => $cover, 316 | "lrc" => $lyric 317 | ); 318 | } 319 | 320 | $this->set_cache($key, $album, 24); 321 | return $this->addNonce($album, $site); 322 | } 323 | 324 | return false; 325 | } 326 | 327 | public function playlist($site, $playlist_id) 328 | { 329 | $Meting = new \Metowolf\Meting($site); 330 | $cache_key = "/$site/playlist/$playlist_id"; 331 | 332 | $cache = $this->get_cache($cache_key); 333 | if ($cache) { 334 | return $this->addNonce($cache, $site); 335 | } 336 | 337 | $proxy = $this->settings('proxy'); 338 | if (!empty($proxy)) $Meting->proxy($proxy); 339 | 340 | $cookies = $this->settings('netease_cookies'); 341 | if (!empty($cookies) && $site === "netease") $Meting->cookie($cookies); 342 | 343 | $response = json_decode($Meting->format()->playlist($playlist_id), true); 344 | 345 | if (!empty($response[0])) { 346 | //处理音乐信息 347 | $result = $response; 348 | $count = count($result); 349 | 350 | if ($count < 1) { 351 | return false; 352 | } 353 | 354 | $playlist = array( 355 | "playlist_id" => $playlist_id, 356 | "playlist_type" => "playlists", 357 | "playlist_count" => $count 358 | ); 359 | 360 | foreach ($result as $k => $value) { 361 | $mp3_url = admin_url() . "admin-ajax.php" . "?action=hermit&scope=" . $site . "_song_url&id=" . $value["url_id"]; 362 | $artists = $value["artist"]; 363 | $artists = implode(",", $artists); 364 | $cover = $this->pic_url($site, $value['id'], $value['pic_id']); 365 | $lyric = admin_url() . "admin-ajax.php" . "?action=hermit&scope=" . $site . "_lyric&id=" . $value['lyric_id']; 366 | $playlist["songs"][] = array( 367 | "id" => $value["id"], 368 | "title" => $value["name"], 369 | "url" => $mp3_url, 370 | "author" => $artists, 371 | "pic" => $cover, 372 | "lrc" => $lyric 373 | ); 374 | } 375 | 376 | $this->set_cache($cache_key, $playlist, 24); 377 | return $this->addNonce($playlist, $site); 378 | } 379 | 380 | return false; 381 | } 382 | 383 | private function addNonce($data, $site, $single = false) 384 | { 385 | if(!$this->settings('low_security')){ 386 | if ($single) { 387 | $data['url'] = $data['url'] . "&_nonce=".wp_create_nonce($site . "_song_url#:".$data['id']); 388 | //$data['pic'] = $data['pic'] . "&_nonce=".wp_create_nonce($site . "_pic_url#:".$data['id']); 389 | $data['lrc'] = $data['lrc'] . "&_nonce=".wp_create_nonce($site . "_lyric#:".$data['id']); 390 | } else { 391 | foreach ($data["songs"] as $key => $value) { 392 | $data["songs"][$key]['url'] = $value['url'] . "&_nonce=".wp_create_nonce($site . "_song_url#:".$value['id']); 393 | //$data["songs"][$key]['pic'] = $value['pic'] . "&_nonce=".wp_create_nonce($site . "_pic_url#:".$value['id']); 394 | $data["songs"][$key]['lrc'] = $value['lrc'] . "&_nonce=".wp_create_nonce($site . "_lyric#:".$value['id']); 395 | } 396 | } 397 | } else { 398 | if ($single) { 399 | $data['url'] = $data['url'] . "&_nonce=".md5(NONCE_KEY.$site . "_song_url#:".$data['id'].NONCE_KEY); 400 | //$data['pic'] = $data['pic'] . "&_nonce=".md5(NONCE_KEY.$site . "_pic_url#:".$data['id'].NONCE_KEY); 401 | $data['lrc'] = $data['lrc'] . "&_nonce=".md5(NONCE_KEY.$site . "_lyric#:".$data['id'].NONCE_KEY); 402 | } else { 403 | foreach ($data["songs"] as $key => $value) { 404 | $data["songs"][$key]['url'] = $value['url'] . "&_nonce=".md5(NONCE_KEY.$site . "_song_url#:".$value['id'].NONCE_KEY); 405 | //$data["songs"][$key]['pic'] = $value['pic'] . "&_nonce=".md5(NONCE_KEY.$site . "_pic_url#:".$value['id'].NONCE_KEY); 406 | $data["songs"][$key]['lrc'] = $value['lrc'] . "&_nonce=".md5(NONCE_KEY.$site . "_lyric#:".$value['id'].NONCE_KEY); 407 | } 408 | } 409 | } 410 | 411 | return $data; 412 | } 413 | 414 | public function curl($API) 415 | { 416 | $curl=curl_init(); 417 | if (isset($API['body'])) { 418 | $API['url']=$API['url'].'?'.http_build_query($API['body']); 419 | } 420 | curl_setopt($curl, CURLOPT_URL, $API['url']); 421 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 422 | curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10); 423 | curl_setopt($curl, CURLOPT_COOKIE, $API['cookie']); 424 | curl_setopt($curl, CURLOPT_REFERER, $API['referer']); 425 | curl_setopt($curl, CURLOPT_USERAGENT, $API['useragent']); 426 | if ($this->settings('proxy')) { 427 | curl_setopt($curl, CURLOPT_PROXY, $this->settings('proxy')); 428 | } 429 | 430 | $result=curl_exec($curl); 431 | curl_close($curl); 432 | return $result; 433 | } 434 | 435 | public function get_cache($key) 436 | { 437 | $cache = get_transient($key); 438 | return $cache === false ? false : json_decode($cache, true); 439 | } 440 | 441 | public function set_cache($key, $value, $hour = 0.1) 442 | { 443 | $value = json_encode($value); 444 | set_transient($key, $value, 60 * 60 * $hour); 445 | } 446 | 447 | public function clear_cache($key) 448 | { 449 | //delete_transient($key); 450 | } 451 | 452 | /** 453 | * settings - 插件设置 454 | * 455 | * @param $key 456 | * 457 | * @return bool 458 | */ 459 | public function settings($key) 460 | { 461 | global $HMT; 462 | return $HMT->settings($key); 463 | } 464 | 465 | } 466 | -------------------------------------------------------------------------------- /assets/js/hermit-library.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name Hermit 3 | * @version 1.9 4 | * @create 2014-02-07 5 | * @lastmodified 2015-09-15 17:36 6 | * @description Hermit Plugin 7 | * @author MuFeng (http://mufeng.me) 8 | * @url http://mufeng.me/hermit-for-wordpress.html 9 | **/ 10 | 11 | jQuery(document).ready(function ($) { 12 | var formSrc = $("#hermit-form-template").html(), 13 | formTmpl = Handlebars.compile(formSrc), 14 | 15 | navSrc = $("#hermit-nav-template").html(), 16 | navTmpl = Handlebars.compile(navSrc), 17 | 18 | navigationSrc = $("#hermit-navigation-template").html(), 19 | navigationTmpl = Handlebars.compile(navigationSrc), 20 | 21 | tableSrc = $("#hermit-table-template").html(), 22 | tableTmpl = Handlebars.compile(tableSrc), 23 | 24 | lrcSrc = $("#hermit-lrc-template").html(), 25 | lrcTmpl = Handlebars.compile(lrcSrc), 26 | 27 | catmovSrc = $("#hermit-move-cat-template").html(), 28 | catmovTmpl = Handlebars.compile(catmovSrc), 29 | 30 | manageSrc = $("#hermit-manage-cat-template").html(), 31 | manageTmpl = Handlebars.compile(manageSrc), 32 | 33 | $bodyLoader = $.mxloader('#wpwrap', true); 34 | 35 | Handlebars.registerHelper('catName', function (catid) { 36 | var html; 37 | 38 | for (var i = 0; i < hermit.catList.length; i++) { 39 | if (catid == hermit.catList[i].id) { 40 | html = '' + hermit.catList[i].title + ''; 41 | break; 42 | } 43 | } 44 | 45 | return html; 46 | }); 47 | 48 | Handlebars.registerHelper('catNav', function (arr, count) { 49 | var html, 50 | _class; 51 | 52 | _class = hermit.currentCatId == 0 ? ' class="current"' : ''; 53 | html = '
    • 全部(' + count + ')
    • '; 54 | _class = ''; 55 | 56 | $.each(arr, function (idx, val) { 57 | _class = val.id == hermit.currentCatId ? ' class="current"' : ''; 58 | html += '
    • |' + val.title + '(' + val.count + ')
    • '; 59 | }); 60 | 61 | return html; 62 | }); 63 | 64 | Handlebars.registerHelper('catOption', function (arr, song_cat) { 65 | var html = ''; 66 | 67 | $.each(arr, function (idx, val) { 68 | var _checked = val.id == song_cat ? ' selected="selected"' : ''; 69 | html += ''; 70 | }); 71 | 72 | return html; 73 | }); 74 | 75 | Handlebars.registerHelper('catCover', function (cover_url, name) { 76 | var html; 77 | 78 | if (cover_url != "")html = '图片加载失败'; 79 | else html = '

      没有封面图

      ' 80 | 81 | return html; 82 | }); 83 | 84 | Handlebars.registerHelper('catLrc', function (index) { 85 | var html; 86 | 87 | html = '显示歌词'; 88 | 89 | return html; 90 | }); 91 | 92 | Handlebars.registerHelper('catAction', function (id) { 93 | var html = ''; 94 | 95 | if (id !== '1') { 96 | html = '编辑 | 删除'; 97 | } else { 98 | html = '

      默认分类禁止编辑/删除

      ' 99 | } 100 | 101 | return html; 102 | }); 103 | 104 | //上传mp3 105 | $('body').on('click', '#hermit-form-song_url-upload', function(){ 106 | /** 107 | * 采用 3.5之后的新上传图片方法 108 | * 不再支持3.5以下 Wordpress 版本 109 | */ 110 | 111 | // Create the media frame. 112 | var file_frame = wp.media.frames.file_frame = wp.media({ 113 | title: '上传本地音乐(推荐 mp3 格式,尽量用英文名称)', 114 | multiple: false // Set to true to allow multiple files to be selected 115 | }); 116 | 117 | // When an image is selected, run a callback. 118 | file_frame.on( 'select', function() { 119 | var attachment = file_frame.state().get('selection').first().toJSON(); 120 | $('#hermit-form-song_url').val(attachment.url); 121 | }); 122 | 123 | // Finally, open the modal 124 | file_frame.open(); 125 | }); 126 | 127 | //上传封面图片 128 | $('body').on('click', '#hermit-form-song_cover-upload', function(){ 129 | /** 130 | * 采用 3.5之后的新上传图片方法 131 | * 不再支持3.5以下 Wordpress 版本 132 | */ 133 | 134 | // Create the media frame. 135 | var file_frame = wp.media.frames.file_frame = wp.media({ 136 | title: '上传本地图片(尽量用英文名称)', 137 | multiple: false // Set to true to allow multiple files to be selected 138 | }); 139 | 140 | // When an image is selected, run a callback. 141 | file_frame.on( 'select', function() { 142 | var attachment = file_frame.state().get('selection').first().toJSON(); 143 | $('#hermit-form-song_cover').val(attachment.url); 144 | }); 145 | 146 | // Finally, open the modal 147 | file_frame.open(); 148 | }); 149 | 150 | //新建音乐 151 | $('.add-new-h2').click(function () { 152 | var sobj = { 153 | id: 0, 154 | catList: hermit.catList 155 | }; 156 | 157 | form(sobj) 158 | }); 159 | 160 | //显示歌词 161 | $('.hermit-list-table').on('click', '.hermit-show-lrc', function () { 162 | var $this = $(this), 163 | index = $this.attr('data-index'), 164 | sobj = hermit.data[index], 165 | main_html = lrcTmpl(sobj); 166 | 167 | $.mxlayer({ 168 | title: sobj["song_name"], 169 | main: main_html, 170 | button: "关闭", 171 | width: 720, 172 | height: 720, 173 | confirm: function (that) { 174 | that.fireEvent(); 175 | } 176 | }) 177 | }); 178 | 179 | //编辑 180 | $('.hermit-list-table').on('click', '.hermit-edit', function () { 181 | var $this = $(this), 182 | index = $this.attr('data-index'), 183 | sobj = hermit.data[index]; 184 | 185 | sobj.catList = hermit.catList; 186 | 187 | form(sobj) 188 | }); 189 | 190 | //单个删除 191 | $('.hermit-list-table').on('click', '.hermit-delete', function () { 192 | var $this = $(this), 193 | ids = $this.attr('data-id'); 194 | 195 | dele(ids) 196 | }); 197 | 198 | //选中删除 199 | $('.hermit-selector-button').click(function() { 200 | if ($(this).prev('.hermit-action-selector').val() == 'trash') { 201 | var arr = []; 202 | 203 | $('.cb-select-th').each(function () { 204 | var $this = $(this); 205 | 206 | if ($this.prop("checked")) { 207 | arr.push($this.val()) 208 | } 209 | }); 210 | 211 | arr = arr.join(','); 212 | dele(arr) 213 | } 214 | else if ($(this).prev('.hermit-action-selector').val() == 'movecat') { 215 | var arr = []; 216 | 217 | $('.cb-select-th').each(function () { 218 | var $this = $(this); 219 | 220 | if ($this.prop("checked")) { 221 | arr.push($this.val()) 222 | } 223 | }); 224 | 225 | arr = arr.join(','); 226 | move_cat(arr) 227 | } 228 | }); 229 | 230 | //管理分类 231 | $('.hermit-list-table').on('click', '.hermit-manage-nav', function () { 232 | $.mxlayer({ 233 | title: '分类管理', 234 | main: manageTmpl(hermit), 235 | button: '关闭', 236 | width: 720, 237 | height: 720, 238 | cancel: function () { 239 | }, 240 | confirm: function (that) { 241 | that.fireEvent() 242 | } 243 | }) 244 | }); 245 | 246 | //新建分类 247 | $('body').on('click', '.hermit-new-nav', function () { 248 | var title = window.prompt("新建分类",""); 249 | 250 | if( title ){ 251 | $bodyLoader.showProgress('新建分类中'); 252 | 253 | $.ajax({ 254 | url: hermit.adminUrl, 255 | data: { 256 | type: 'catnew', 257 | title: title 258 | }, 259 | type: 'post', 260 | success: function (data) { 261 | hermit.catList = data; 262 | $bodyLoader.showSuccess('新建分类成功'); 263 | list({ 264 | page: 1, 265 | catid: hermit.currentCatId 266 | }, function () { 267 | initView(); 268 | $('.mxlayer-main-body').html(manageTmpl(hermit)); 269 | }); 270 | }, 271 | error: function () { 272 | $bodyLoader.showError('分类已存在'); 273 | } 274 | }); 275 | } 276 | }); 277 | 278 | //删除分类 279 | $('body').on('click', '.hermit-cat-delete', function () { 280 | var $this = $(this), 281 | id = $this.attr('data-id'); 282 | 283 | if ( id === '1' )return; 284 | 285 | var cofim = window.confirm('确认删除?'); 286 | 287 | if (cofim) { 288 | $bodyLoader.showProgress('删除分类中'); 289 | 290 | $.ajax({ 291 | url: hermit.adminUrl, 292 | type: 'post', 293 | data: { 294 | type: 'catdel', 295 | id: id 296 | }, 297 | success: function (result) { 298 | hermit.catList = result; 299 | $bodyLoader.showSuccess('删除分类成功'); 300 | list({ 301 | page: 1, 302 | catid: hermit.currentCatId 303 | }, function () { 304 | initView(); 305 | $('.mxlayer-main-body').html(manageTmpl(hermit)); 306 | }); 307 | }, 308 | error: function () { 309 | $bodyLoader.showProgress('删除失败,请稍后重试。'); 310 | } 311 | }) 312 | } 313 | }); 314 | 315 | //编辑分类 316 | $('body').on('click', '.hermit-cat-edit', function () { 317 | var title = window.prompt("重命名分类",""), 318 | $this = $(this), 319 | id = $this.attr('data-id'); 320 | 321 | if ( id === '1' )return; 322 | 323 | if( title ){ 324 | $bodyLoader.showProgress('重命名分类中'); 325 | 326 | $.ajax({ 327 | url: hermit.adminUrl, 328 | data: { 329 | type: 'catupd', 330 | title: title, 331 | id: id 332 | }, 333 | type: 'post', 334 | success: function (data) { 335 | hermit.catList = data; 336 | $bodyLoader.showSuccess('重命名分类成功'); 337 | list({ 338 | page: 1, 339 | catid: hermit.currentCatId 340 | }, function () { 341 | initView(); 342 | $('.mxlayer-main-body').html(manageTmpl(hermit)); 343 | }); 344 | }, 345 | error: function () { 346 | $bodyLoader.showError('分类已存在'); 347 | } 348 | }); 349 | } 350 | }); 351 | 352 | //初始化 353 | initView(); 354 | 355 | //监测总数 356 | watch(hermit, 'count', function () { 357 | initCatNav(); 358 | initNavigation(); 359 | }); 360 | 361 | //监测菜单 362 | watch(hermit, 'currentCatId', function () { 363 | list({ 364 | page: 1, 365 | catid: hermit.currentCatId 366 | }, function () { 367 | initView(); 368 | }); 369 | }); 370 | 371 | //监测曲库 372 | watch(hermit, 'data', function () { 373 | initTable() 374 | }); 375 | 376 | //检测分类 377 | watch(hermit, 'catList', function () { 378 | initCatNav(); 379 | }); 380 | 381 | window.showTableByCat = function(catid){ 382 | hermit.currentCatId = catid; 383 | }; 384 | 385 | function initView() { 386 | initCatNav(); 387 | initNavigation(); 388 | initTable(); 389 | } 390 | 391 | function initCatNav() { 392 | $('.subsubsub').html(navTmpl(hermit)); 393 | } 394 | 395 | function initNavigation() { 396 | $('.tablenav-pages').html(navigationTmpl(hermit)) 397 | //分页 398 | .mxpage({ 399 | perPage: 5, 400 | currentPage: 1, //当前页数 401 | maxPage: hermit.maxPage, //最大页数 402 | previousText: '‹', //上一页标题 403 | nextText: '›', //下一页标题 404 | frontPageText: '«', //最前页标题 405 | lastPageText: '»', //最后页标题 406 | click: function (index) { 407 | list({ 408 | page: index, 409 | catid: hermit.currentCatId 410 | }) 411 | } 412 | }); 413 | } 414 | 415 | function initTable() { 416 | $('.wp-list-table tbody').html(tableTmpl(hermit)); 417 | } 418 | 419 | function form(sobj) { 420 | var main_html = formTmpl(sobj), 421 | msg = {}; 422 | 423 | if (sobj.id > 0) { 424 | msg.title = '更新音乐'; 425 | msg.success = '更新成功'; 426 | msg.error = '更新失败,请稍后重试。'; 427 | } else { 428 | msg.title = '新建音乐'; 429 | msg.success = '新建成功'; 430 | msg.error = '新建失败,请稍后重试。'; 431 | } 432 | 433 | $.mxlayer({ 434 | title: msg.title, 435 | main: main_html, 436 | button: msg.title, 437 | width: 720, 438 | height: 720, 439 | cancel: function () { 440 | }, 441 | confirm: function (that) { 442 | var formKey = ['song_name', 'song_author', 'song_url', 'song_cat', 'song_cover', 'song_lrc'], 443 | formObj = {}; 444 | 445 | $bodyLoader.showProgress('数据上传中'); 446 | 447 | for (var i = 0; i < formKey.length; i++) { 448 | var _id = formKey[i], 449 | $elem = $('#hermit-form-' + _id), 450 | val = $elem.val(); 451 | 452 | if (isEmpty(val)) { 453 | if (i < 4) { 454 | $bodyLoader.showError('请输入正确的信息。'); 455 | return false; 456 | } else { 457 | val = ''; 458 | } 459 | } 460 | 461 | formObj[_id] = val 462 | } 463 | 464 | if (sobj.id > 0) { 465 | formObj.id = sobj.id; 466 | formObj.type = 'update'; 467 | } else { 468 | formObj.type = 'new'; 469 | } 470 | 471 | $.ajax({ 472 | url: hermit.adminUrl, 473 | data: formObj, 474 | type: 'post', 475 | success: function (data) { 476 | $bodyLoader.showSuccess(msg.success); 477 | 478 | that.fireEvent(); 479 | 480 | list({ 481 | page: 1, 482 | catid: hermit.currentCatId 483 | }, function () { 484 | initView(); 485 | }); 486 | }, 487 | error: function () { 488 | $bodyLoader.showError(msg.error); 489 | } 490 | }); 491 | } 492 | }) 493 | } 494 | 495 | function list(lobj, callback) { 496 | $bodyLoader.showProgress('音乐加载中'); 497 | 498 | if (lobj.catid > 0) { 499 | lobj = { 500 | type: 'list', 501 | paged: lobj.page, 502 | catid: lobj.catid 503 | } 504 | } else { 505 | lobj = { 506 | type: 'list', 507 | paged: lobj.page 508 | } 509 | } 510 | 511 | $.ajax({ 512 | url: hermit.adminUrl, 513 | data: lobj, 514 | success: function (result) { 515 | $bodyLoader.dismiss(); 516 | 517 | hermit.data = result.data; 518 | 519 | if (callback) { 520 | hermit.count = result.count; 521 | hermit.maxPage = result.maxPage; 522 | hermit.catList = result.catList; 523 | 524 | callback(); 525 | } 526 | }, 527 | error: function () { 528 | $bodyLoader.showError('加载失败'); 529 | } 530 | }) 531 | } 532 | 533 | function dele(ids) { 534 | var cofim = window.confirm('确认删除?'); 535 | 536 | if (cofim) { 537 | $bodyLoader.showProgress('删除音乐中'); 538 | 539 | $.ajax({ 540 | url: hermit.adminUrl, 541 | type: 'post', 542 | data: { 543 | type: 'delete', 544 | ids: ids 545 | }, 546 | success: function (result) { 547 | hermit.catList = result; 548 | list({ 549 | page: 1, 550 | catid: hermit.currentCatId 551 | }, function () { 552 | initView(); 553 | }); 554 | }, 555 | error: function () { 556 | $bodyLoader.showProgress('删除失败,请稍后重试。'); 557 | } 558 | }) 559 | } 560 | } 561 | 562 | function move_cat(ids) { 563 | $.mxlayer({ 564 | title: '选择目标分类', 565 | main: catmovTmpl(hermit), 566 | button: '提交', 567 | width: 720, 568 | height: 220, 569 | cancel: function () { 570 | }, 571 | confirm: function (that) { 572 | $bodyLoader.showProgress('移动音乐中'); 573 | var data = { 574 | type: 'move', 575 | catid: $('#hermit-move-song_cat').val(), 576 | ids: ids 577 | }; 578 | $.ajax({ 579 | url: hermit.adminUrl, 580 | data: data, 581 | type: 'post', 582 | success: function (data) { 583 | $bodyLoader.showSuccess('移动成功'); 584 | 585 | that.fireEvent(); 586 | 587 | list({ 588 | page: 1, 589 | catid: hermit.currentCatId 590 | }, function () { 591 | initView(); 592 | }); 593 | }, 594 | error: function () { 595 | $bodyLoader.showError(msg.error); 596 | } 597 | }); 598 | } 599 | }) 600 | } 601 | 602 | function isEmpty(str) { 603 | if (str == null || str == undefined) { 604 | return true; 605 | } 606 | 607 | return str.replace(/(^\s*)|(\s*$)/g, "").length == 0 608 | } 609 | }); -------------------------------------------------------------------------------- /class.hermit.php: -------------------------------------------------------------------------------- 1 | _settings = get_option('hermit_setting'); 14 | 15 | /** 16 | ** 事件绑定 17 | **/ 18 | add_action('admin_menu', array( 19 | $this, 20 | 'menu', 21 | )); 22 | add_shortcode('hermit', array( 23 | $this, 24 | 'shortcode', 25 | )); 26 | add_action('admin_init', array( 27 | $this, 28 | 'page_init', 29 | )); 30 | add_action('wp_enqueue_scripts', array( 31 | $this, 32 | 'hermit_scripts', 33 | )); 34 | add_filter('plugin_action_links', array( 35 | $this, 36 | 'plugin_action_link', 37 | ), 10, 4); 38 | add_action('wp_ajax_nopriv_hermit', array( 39 | $this, 40 | 'hermit_callback', 41 | )); 42 | add_action('wp_ajax_hermit', array( 43 | $this, 44 | 'hermit_callback', 45 | )); 46 | add_action('in_admin_footer', array( 47 | $this, 48 | 'music_footer', 49 | )); 50 | add_action('wp_ajax_hermit_source', array( 51 | $this, 52 | 'hermit_source_callback', 53 | )); 54 | add_action('wp_footer', array( 55 | $this, 56 | 'aplayer_init', 57 | )); 58 | add_action('admin_enqueue_scripts', array( 59 | $this, 60 | 'cookies_pointer', 61 | )); 62 | add_action('wp_ajax_hermit_ignore_cookies_pointer', array( 63 | $this, 64 | 'ignore_cookies_pointer', 65 | )); 66 | add_action('enqueue_block_editor_assets', array( 67 | $this, 68 | 'hermitx_editor_assets' 69 | )); 70 | } 71 | 72 | /** 73 | * 载入所需要的CSS和js文件 74 | */ 75 | public function hermit_scripts() 76 | { 77 | $strategy = $this->settings('strategy'); 78 | $globalPlayer = $this->settings('globalPlayer'); 79 | 80 | if ($strategy == 1 && $globalPlayer == 0) { 81 | global $post, $posts; 82 | foreach ($posts as $post) { 83 | if (has_shortcode($post->post_content, 'hermit')) { 84 | $this->_load_scripts(); 85 | break; 86 | } 87 | } 88 | } else { 89 | $this->_load_scripts(); 90 | } 91 | } 92 | 93 | /** 94 | * 加载资源 95 | */ 96 | private function _load_scripts() 97 | { 98 | $this->_css('APlayer.min'); 99 | $this->_js('APlayer.min', $this->settings('jsplace')); 100 | if (!$this->settings('debug')) { 101 | $this->_js('hermit-load.min', 1); 102 | } else { 103 | $this->_js('hermit-load', 1); 104 | } 105 | } 106 | 107 | /** 108 | * 添加文章短代码 109 | */ 110 | public function shortcode($atts, $content = null) 111 | { 112 | if (empty($atts["theme"])) { 113 | $color = $this->settings('color'); 114 | } else { 115 | $color = $atts["theme"]; 116 | } 117 | switch ($color) { 118 | case 'default': 119 | $color = "#5895be"; 120 | break; 121 | case 'red': 122 | $color = "#dd4b39"; 123 | break; 124 | case 'blue': 125 | $color = "#5cb85c"; 126 | break; 127 | case 'yellow': 128 | $color = "#f0ad4e"; 129 | break; 130 | case 'pink': 131 | $color = "#f489ad"; 132 | break; 133 | case 'purple': 134 | $color = "#da70d6"; 135 | break; 136 | case 'black': 137 | $color = "#aaaaaa"; 138 | break; 139 | case 'customize': 140 | $color = $this->settings('color_customize'); 141 | break; 142 | default: 143 | break; 144 | } 145 | $atts["theme"] = $color; 146 | $atts["songs"] = $content; 147 | if ($this->settings('listFolded') == 1) { 148 | $atts["listfolded"] = 'true'; 149 | } 150 | 151 | $atts["mode"] = strtolower($atts["mode"]); 152 | 153 | switch ($atts["mode"]) { 154 | case 'random': 155 | $atts["loop"] = 'all'; 156 | $atts["order"] = 'random'; 157 | break; 158 | case 'order': 159 | $atts["loop"] = 'none'; 160 | $atts["order"] = 'list'; 161 | break; 162 | case 'single': 163 | $atts["loop"] = 'one'; 164 | $atts["order"] = 'list'; 165 | break; 166 | default: 167 | $atts["loop"] = 'all'; 168 | $atts["order"] = 'list'; 169 | break; 170 | } 171 | 172 | unset($atts["mode"]); 173 | 174 | $atts["_nonce"] = $this->settings('low_security') ? md5(NONCE_KEY . $content . NONCE_KEY) : wp_create_nonce($content); 175 | 176 | $playlist_max_height = $this->settings('playlist_max_height'); 177 | if ($playlist_max_height != 0 && empty($atts["listmaxheight"])) { 178 | $atts["listmaxheight"] = $playlist_max_height . "px"; 179 | } 180 | 181 | $keys = array_keys($atts); 182 | $apatts = ""; 183 | foreach ($keys as $value) { 184 | if ($value == "auto") { 185 | $apatts = $apatts . 'data-autoplay="' . (($atts[$value] == 1) ? "true" : "false") . '" '; 186 | continue; 187 | } 188 | 189 | $apatts = $apatts . 'data-' . $value . '="' . $atts[$value] . '" '; 190 | } 191 | 192 | return '
      '; 193 | } 194 | 195 | /** 196 | * 添加写文章按钮 197 | */ 198 | public function custom_button($context) 199 | { 200 | $context .= " 添加音乐"; 201 | 202 | return $context; 203 | } 204 | 205 | public function nonce_verify() 206 | { 207 | if (!isset($_GET['musicset'])) { 208 | if (!$this->settings('low_security')) { 209 | $result = wp_verify_nonce($_GET['_nonce'], $_GET['scope'] . '#:' . $_GET['id']); 210 | } else { 211 | $result = md5(NONCE_KEY . $_GET['scope'] . '#:' . $_GET['id'] . NONCE_KEY) === $_GET['_nonce']; 212 | } 213 | } else { 214 | if (!$this->settings('low_security')) { 215 | $result = wp_verify_nonce($_GET['_nonce'], $_GET['musicset']); 216 | } else { 217 | $result = md5(NONCE_KEY . $_GET['musicset'] . NONCE_KEY) === $_GET['_nonce']; 218 | } 219 | } 220 | 221 | if (!$result) { 222 | http_response_code(401); 223 | header('Content-type: application/json;charset=UTF-8'); 224 | $result = array( 225 | 'status' => 401, 226 | 'msg' => $result, 227 | ); 228 | die(json_encode($result)); 229 | } 230 | return true; 231 | } 232 | /** 233 | * JSON 音乐数据 234 | */ 235 | public function hermit_callback() 236 | { 237 | if (!empty($_SERVER["HTTP_REFERER"])) { 238 | $referer = parse_url($_SERVER["HTTP_REFERER"]); 239 | $host = strtolower($referer['host']); 240 | } 241 | if (empty($_SERVER["HTTP_REFERER"]) || $host === parse_url(home_url())['host']) { 242 | if (!isset($_GET['musicset'])) { 243 | $this->hermit_route($_GET["scope"], $_GET["id"]); 244 | } else { 245 | $this->nonce_verify(); 246 | $result = array( 247 | 'status' => 200, 248 | 'msg' => array( 'songs' => [], ), 249 | ); 250 | $musicSet = explode(";", $_GET["musicset"]); 251 | foreach ($musicSet as $key => $music) { 252 | $musicInfo = explode("#:", $music); 253 | $currentResult = $this->hermit_route($musicInfo[0], $musicInfo[1])["msg"]["songs"]; 254 | if (count($currentResult) < 1) { 255 | continue; 256 | } 257 | $result["msg"]["songs"] = array_merge($result["msg"]["songs"], $currentResult); 258 | } 259 | } 260 | } else { 261 | $result = array( 262 | 'status' => 401, 263 | 'msg' => null, 264 | ); 265 | } 266 | 267 | //输出 JSON 268 | header('Content-type: application/json;charset=UTF-8'); 269 | exit(json_encode($result)); 270 | } 271 | 272 | private function hermit_route($scope, $id) 273 | { 274 | global $HMTJSON; 275 | switch ($scope) { 276 | //本地音乐部分 277 | case 'remote': 278 | $this->nonce_verify(); 279 | $result = array( 280 | 'status' => 200, 281 | 'msg' => $this->music_remote($id), 282 | ); 283 | break; 284 | case 'remote_lyric': 285 | echo $this->remote_lrc($id); 286 | exit; 287 | 288 | //默认路由 289 | default: 290 | $re = '/^(?(netease|xiami|tencent|kugou|baidu)?)_?(?songs|songlist|album|playlist|collect|artist|song_url|lyric|id_parse)$/i'; 291 | preg_match($re, $scope, $matches); 292 | if (!empty($matches['scope'])) { 293 | $scope = $matches['scope']; 294 | if (empty($matches['site'])) { 295 | $site = 'xiami'; 296 | } else { 297 | $site = $matches['site']; 298 | } 299 | if ($scope === 'songs') { 300 | $scope = 'songlist'; 301 | } elseif ($scope === 'collect') { 302 | $scope = 'playlist'; 303 | } 304 | 305 | if (method_exists($HMTJSON, $scope)) { 306 | // if ($scope === 'pic_url') { 307 | // $this->nonce_verify(); 308 | // $result = array( 309 | // 'status' => 200, 310 | // 'msg' => $HMTJSON->$scope($site, $id, $_GET['picid']) 311 | // ); 312 | //} 313 | if ($scope === 'id_parse') { 314 | if (array_intersect($this->settings('roles'), wp_get_current_user()->roles)){ 315 | $result = array( 316 | 'status' => 200, 317 | 'msg' => $HMTJSON->$scope($site, explode(',', $_GET['src'])), 318 | ); 319 | } else { 320 | $result = array( 321 | 'status' => 401, 322 | 'msg' => false, 323 | ); 324 | } 325 | } elseif ($scope === 'lyric') { 326 | $this->nonce_verify(); 327 | echo $HMTJSON->$scope($site, $_GET['id']); 328 | exit; 329 | } else { 330 | if (!isset($_GET['musicset'])){ 331 | $this->nonce_verify(); 332 | } 333 | 334 | $result = array( 335 | 'status' => 200, 336 | 'msg' => $HMTJSON->$scope($site, $id), 337 | ); 338 | } 339 | } else { 340 | $result = array( 341 | 'status' => 400, 342 | 'msg' => null, 343 | ); 344 | } 345 | } else { 346 | $result = array( 347 | 'status' => 400, 348 | 'msg' => null, 349 | ); 350 | } 351 | } 352 | 353 | return $result; 354 | } 355 | 356 | /** 357 | * 输出json数据 358 | */ 359 | public function hermit_source_callback() 360 | { 361 | $type = $_REQUEST['type']; 362 | 363 | switch ($type) { 364 | case 'new': 365 | $result = $this->music_new(); 366 | $this->success_response($result); 367 | break; 368 | 369 | case 'delete': 370 | $this->music_delete(); 371 | $data = $this->music_catList(); 372 | $this->success_response($data); 373 | break; 374 | 375 | case 'move': 376 | $this->music_cat_move(); 377 | $this->success_response(array()); 378 | break; 379 | 380 | case 'update': 381 | $result = $this->music_update(); 382 | $this->success_response($result); 383 | break; 384 | 385 | case 'list': 386 | $paged = intval($this->get('paged')); 387 | $catid = $this->get('catid'); 388 | $prePage = $this->settings('prePage'); 389 | 390 | $catid = $catid ? $catid : null; 391 | 392 | $data = $this->music_list($paged, $catid); 393 | $count = intval($this->music_count()); // 歌曲总数 394 | $catList = $this->music_catList(); 395 | if ($catid == null) { 396 | $cat_count = $count; 397 | } else { 398 | $cat_count = intval($this->music_count($catid)); 399 | } 400 | $maxPage = ceil($cat_count / $prePage); 401 | 402 | $result = compact('data', 'paged', 'maxPage', 'count', 'catList'); 403 | $this->success_response($result); 404 | break; 405 | 406 | case 'catlist': 407 | $data = $this->music_catList(); 408 | $this->success_response($data); 409 | break; 410 | 411 | case 'catnew': 412 | $title = $this->post('title'); 413 | 414 | if ($this->music_cat_existed($title)) { 415 | $data = "分类名称已存在"; 416 | $this->error_response(500, $data); 417 | } else { 418 | $this->music_cat_new($title); 419 | $data = $this->music_catList(); 420 | $this->success_response($data); 421 | } 422 | break; 423 | 424 | case 'catupd': 425 | $result = $this->cat_updata(); 426 | $this->success_response($result); 427 | break; 428 | 429 | case 'catdel': 430 | $this->cat_delete(); 431 | $data = $this->music_catList(); 432 | $this->success_response($data); 433 | break; 434 | 435 | default: 436 | $data = "不存在的请求."; 437 | $this->error_response(400, $data); 438 | } 439 | } 440 | 441 | /** 442 | * 添加写文章所需要的js和css 443 | */ 444 | public function page_init() 445 | { 446 | global $pagenow; 447 | 448 | $allowed_roles = $this->settings('roles'); 449 | $user = wp_get_current_user(); 450 | 451 | if (array_intersect($allowed_roles, $user->roles)) { 452 | if ($pagenow == "post-new.php" || $pagenow == "post.php") { 453 | add_action('media_buttons_context', array( 454 | $this, 455 | 'custom_button', 456 | )); 457 | 458 | $this->_css('hermit-post'); 459 | $this->_libjs('handlebars'); 460 | $this->_js('hermit-post'); 461 | 462 | $prePage = $this->settings('prePage'); 463 | $count = $this->music_count(); 464 | $maxPage = ceil($count / $prePage); 465 | $roles = $user->roles; 466 | 467 | wp_localize_script('hermit-post', 'hermit', array( 468 | "ajax_url" => admin_url() . "admin-ajax.php", 469 | "max_page" => $maxPage, 470 | "roles" => $roles, 471 | "plugin_url" => HERMIT_URL, 472 | )); 473 | } 474 | 475 | if ($pagenow == "admin.php" && $_GET['page'] == 'hermit') { 476 | //上传音乐支持 477 | wp_enqueue_media(); 478 | $this->_css('hermit-library'); 479 | $this->_libjs('watch,handlebars,jquery.mxloader,jquery.mxpage,jquery.mxlayer'); 480 | $this->_js('hermit-library'); 481 | } 482 | } 483 | } 484 | 485 | /** 486 | * 显示后台菜单 487 | */ 488 | public function menu() 489 | { 490 | add_menu_page('Hermit X 播放器', 'Hermit X 播放器', 'manage_options', 'hermit', array( 491 | $this, 492 | 'library', 493 | ), HERMIT_URL . '/assets/images/logo.png'); 494 | add_submenu_page('hermit', '音乐库', '音乐库', 'manage_options', 'hermit', array( 495 | $this, 496 | 'library', 497 | )); 498 | add_submenu_page('hermit', '设置', '设置', 'manage_options', 'hermit-setting', array( 499 | $this, 500 | 'setting', 501 | )); 502 | 503 | add_action('admin_init', array( 504 | $this, 505 | 'hermit_setting', 506 | )); 507 | } 508 | 509 | /** 510 | * 音乐库 library 511 | */ 512 | public function library() 513 | { 514 | @require_once 'include/library.php'; 515 | } 516 | 517 | /** 518 | * 设置 519 | */ 520 | public function setting() 521 | { 522 | @require_once 'include/setting.php'; 523 | } 524 | 525 | /** 526 | * 注册设置数组 527 | */ 528 | public function hermit_setting() 529 | { 530 | register_setting('hermit_setting_group', 'hermit_setting'); 531 | } 532 | 533 | /** 534 | * 添加<音乐库>按钮 535 | */ 536 | public function plugin_action_link($actions, $plugin_file, $plugin_data) 537 | { 538 | if (strpos($plugin_file, 'hermit') !== false && is_plugin_active($plugin_file)) { 539 | $_actions = array( 540 | 'option' => '音乐库', 541 | ); 542 | $actions = array_merge($_actions, $actions); 543 | } 544 | 545 | return $actions; 546 | } 547 | 548 | /** 549 | * Handlebars 模板 550 | */ 551 | public function music_footer() 552 | { 553 | global $pagenow; 554 | if ($pagenow == "post-new.php" || $pagenow == "post.php") { 555 | @require_once 'include/template.php'; 556 | } 557 | } 558 | 559 | /** 560 | * settings - 插件设置 561 | * 562 | * @param $key 563 | * 564 | * @return bool 565 | */ 566 | public function settings($key) 567 | { 568 | $defaults = array( 569 | 'strategy' => 1, 570 | 'color' => 'default', 571 | 'playlist_max_height' => '349', 572 | 'quality' => '320', 573 | 'jsplace' => 0, 574 | 'prePage' => 20, 575 | 'remainTime' => 10, 576 | 'roles' => array( 577 | 'administrator', 578 | ), 579 | 'debug' => false, 580 | 'color_customize' => '#5895be', 581 | 'netease_cookies' => '', 582 | 'low_security' => 0, 583 | 'globalPlayer' => 0, 584 | 'listFolded' => 0, 585 | 'proxy' => '', 586 | 'assetsPublicCDN' => 1, 587 | ); 588 | 589 | $settings = $this->_settings; 590 | $settings = wp_parse_args($settings, $defaults); 591 | 592 | return $settings[$key]; 593 | } 594 | 595 | public function cookies_pointer() 596 | { 597 | if (in_array('hermit-cookies-setting', $this->get_current_dismissed())) { 598 | return; 599 | } 600 | 601 | if (!current_user_can('manage_options')) { 602 | return; 603 | } 604 | 605 | wp_enqueue_style('wp-pointer'); 606 | wp_enqueue_script('wp-pointer'); 607 | 608 | $filename = HERMIT_PATH . '/include/cookies-pointer.php'; 609 | $callback = require $filename; 610 | 611 | $ignore = add_query_arg(array( 612 | 'action' => 'hermit_ignore_cookies_pointer', 613 | '_wpnonce' => wp_create_nonce('hermit-ignore-cookies-pointer'), 614 | ), admin_url('admin-ajax.php')); 615 | 616 | ob_start(); 617 | call_user_func($callback, $ignore); 618 | 619 | $code = ob_get_clean(); 620 | wp_add_inline_script('wp-pointer', $code); 621 | } 622 | 623 | public function ignore_cookies_pointer() 624 | { 625 | check_ajax_referer('hermit-ignore-cookies-pointer'); 626 | $dismissed = $this->get_current_dismissed(); 627 | 628 | if (in_array('hermit-cookies-setting', $dismissed)) { 629 | return; 630 | } 631 | 632 | if (!current_user_can('manage_options')) { 633 | return; 634 | } 635 | 636 | $user_id = get_current_user_id(); 637 | $dismissed[] = 'hermit-cookies-setting'; 638 | 639 | if (update_user_meta($user_id, 'dismissed_wp_pointers', implode(',', $dismissed))) { 640 | wp_die(1); 641 | } 642 | } 643 | 644 | private function get_current_dismissed() 645 | { 646 | $dismissed = get_user_meta(get_current_user_id(), 'dismissed_wp_pointers', true); 647 | return array_filter(explode(',', (string) $dismissed)); 648 | } 649 | 650 | private function music_remote($ids) 651 | { 652 | global $wpdb, $hermit_table_name, $HMTJSON; 653 | 654 | $key = "/remote/song/$ids"; 655 | $cache = $HMTJSON->get_cache($key); 656 | if(!empty($cache)){ 657 | return $cache; 658 | } 659 | 660 | $result = array(); 661 | $data = $wpdb->get_results("SELECT id,song_name,song_author,song_url,song_cover FROM {$hermit_table_name} WHERE id in ({$ids}) order by field(id, {$ids})"); 662 | 663 | foreach ($data as $key => $value) { 664 | $result['songs'][] = array( 665 | "id" => $value->id, 666 | "title" => $value->song_name, 667 | "author" => $value->song_author, 668 | "url" => $value->song_url, 669 | "pic" => $value->song_cover, 670 | "lrc" => admin_url() . "admin-ajax.php" . "?action=hermit&scope=remote_lyric&id=" . $value->id 671 | ); 672 | } 673 | 674 | $HMTJSON->set_cache($key, $result, 128); 675 | return $result; 676 | } 677 | 678 | /** 679 | * 本地歌词 680 | */ 681 | private function remote_lrc($id) 682 | { 683 | global $HMTJSON; 684 | 685 | $key = "/remote/lyric/$id"; 686 | $cache = $HMTJSON->get_cache($key); 687 | if(!empty($cache)){ 688 | return $cache; 689 | } 690 | 691 | global $wpdb, $hermit_table_name; 692 | 693 | $data = $wpdb->get_results($wpdb->prepare("SELECT song_lrc FROM `$hermit_table_name` WHERE id = %d", $id)); 694 | if (count($data) < 0) $result = ""; 695 | else $result = $data[0]->song_lrc; 696 | 697 | $HMTJSON->set_cache($key, $result, 128); 698 | return $result; 699 | } 700 | 701 | private function localMusicImage() 702 | { 703 | //咕咕咕 704 | } 705 | 706 | /** 707 | * 新增本地音乐 708 | */ 709 | private function music_new() 710 | { 711 | global $wpdb, $hermit_table_name; 712 | 713 | $song_name = stripslashes($this->post('song_name')); 714 | $song_author = stripslashes($this->post('song_author')); 715 | $song_url = esc_attr(esc_html($this->post('song_url'))); 716 | $song_cover = esc_attr(esc_html($this->post('song_cover'))); 717 | $song_lrc = stripslashes($this->post('song_lrc')); 718 | $song_cat = $this->post('song_cat'); 719 | $created = date('Y-m-d H:i:s'); 720 | 721 | $wpdb->insert($hermit_table_name, compact('song_name', 'song_author', 'song_url', 'song_cover', 'song_lrc', 'song_cat', 'created'), array( 722 | '%s', 723 | '%s', 724 | '%s', 725 | '%s', 726 | '%s', 727 | '%d', 728 | '%s', 729 | )); 730 | $id = $wpdb->insert_id; 731 | 732 | $song_cat_name = $this->music_cat($song_cat); 733 | 734 | return compact('id', 'song_name', 'song_author', 'song_cat', 'song_cat_name', 'song_url', 'song_cover', 'song_lrc'); 735 | } 736 | 737 | /** 738 | * 升级本地音乐信息 739 | */ 740 | private function music_update() 741 | { 742 | global $wpdb, $hermit_table_name; 743 | 744 | $id = $this->post('id'); 745 | $song_name = stripslashes($this->post('song_name')); 746 | $song_author = stripslashes($this->post('song_author')); 747 | $song_url = esc_attr(esc_html($this->post('song_url'))); 748 | $song_cover = esc_attr(esc_html($this->post('song_cover'))); 749 | $song_lrc = stripslashes($this->post('song_lrc')); 750 | $song_cat = $this->post('song_cat'); 751 | 752 | $wpdb->update($hermit_table_name, compact('song_name', 'song_author', 'song_cat', 'song_url', 'song_cover', 'song_lrc'), array( 753 | 'id' => $id 754 | ), array( 755 | '%s', 756 | '%s', 757 | '%d', 758 | '%s', 759 | '%s', 760 | '%s' 761 | ), array( 762 | '%d', 763 | )); 764 | 765 | $song_cat_name = $this->music_cat($song_cat); 766 | 767 | delete_transient("/remote/lyric/$id"); 768 | delete_transient("/remote/song/$id"); 769 | return compact('id', 'song_name', 'song_author', 'song_cat', 'song_cat_name', 'song_url', 'song_cover', 'song_lrc'); 770 | } 771 | 772 | /** 773 | * 删除本地音乐 774 | */ 775 | private function music_delete() 776 | { 777 | global $wpdb, $hermit_table_name; 778 | 779 | $ids = $this->post('ids'); 780 | 781 | $wpdb->query("DELETE FROM {$hermit_table_name} WHERE id IN ({$ids})"); 782 | } 783 | 784 | /** 785 | * 移动分类 786 | */ 787 | private function music_cat_move() 788 | { 789 | global $wpdb, $hermit_table_name; 790 | 791 | $ids = $this->post('ids'); 792 | $catid = $this->post('catid'); 793 | 794 | $wpdb->query("UPDATE {$hermit_table_name} SET song_cat = {$catid} WHERE id IN ({$ids})"); 795 | } 796 | 797 | /** 798 | * 本地音乐列表 799 | * 800 | * @param $paged 801 | * @param null $catid 802 | * 803 | * @return mixed 804 | */ 805 | private function music_list($paged, $catid = null) 806 | { 807 | global $wpdb, $hermit_table_name; 808 | 809 | $limit = $this->settings('prePage'); 810 | $offset = ($paged - 1) * $limit; 811 | 812 | if ($catid) { 813 | $query_str = "SELECT id,song_name,song_author,song_cat,song_url,song_cover,song_lrc,created FROM {$hermit_table_name} WHERE `song_cat` = '{$catid}' ORDER BY `created` DESC LIMIT {$limit} OFFSET {$offset}"; 814 | } else { 815 | $query_str = "SELECT id,song_name,song_author,song_cat,song_url,song_cover,song_lrc,created FROM {$hermit_table_name} ORDER BY `created` DESC LIMIT {$limit} OFFSET {$offset}"; 816 | } 817 | 818 | $result = $wpdb->get_results($query_str); 819 | 820 | // 将lrc转成html格式 821 | for ($i = 0; $i < count($result); $i++) { 822 | if ($result[$i]->song_lrc == "") $result[$i]->song_lrc_html = "没有歌词
      "; 823 | else $result[$i]->song_lrc_html = str_replace("\n", "
      ", $result[$i]->song_lrc); 824 | } 825 | 826 | return $result; 827 | } 828 | 829 | /** 830 | * 本地音乐分类列表 831 | * 832 | * @return mixed 833 | */ 834 | private function music_catList() 835 | { 836 | global $wpdb, $hermit_cat_name; 837 | 838 | $query_str = "SELECT id,title FROM {$hermit_cat_name}"; 839 | $result = $wpdb->get_results($query_str); 840 | 841 | if (!empty($result)) { 842 | foreach ($result as $key => $val) { 843 | $result[$key]->count = intval($this->music_count($val->id)); 844 | } 845 | } 846 | 847 | return $result; 848 | } 849 | 850 | /** 851 | * 本地分类名称 852 | * 853 | * @param $cat_id 854 | * 855 | * @return mixed 856 | */ 857 | private function music_cat($cat_id) 858 | { 859 | global $wpdb, $hermit_cat_name; 860 | 861 | $cat_name = $wpdb->get_var("SELECT title FROM {$hermit_cat_name} WHERE id = '{$cat_id}'"); 862 | 863 | return $cat_name; 864 | } 865 | 866 | /** 867 | * 判断分类是否存在 868 | * 869 | * @param $title 870 | * 871 | * @return mixed 872 | */ 873 | private function music_cat_existed($title) 874 | { 875 | global $wpdb, $hermit_cat_name; 876 | 877 | $id = $wpdb->get_var("SELECT id FROM {$hermit_cat_name} WHERE title = '{$title}'"); 878 | 879 | return $id; 880 | } 881 | 882 | /** 883 | * 新建分类 884 | */ 885 | private function music_cat_new($title) 886 | { 887 | global $wpdb, $hermit_cat_name; 888 | 889 | $title = stripslashes($title); 890 | 891 | $wpdb->insert($hermit_cat_name, compact('title'), array( 892 | '%s', 893 | )); 894 | 895 | $new_cat_id = $wpdb->insert_id; 896 | 897 | return array( 898 | 'id' => $new_cat_id, 899 | 'title' => $title, 900 | 'count' => intval($this->music_count($new_cat_id)), 901 | ); 902 | } 903 | 904 | /** 905 | * 删除本地分类 906 | * 907 | * @return boolean 908 | */ 909 | private function cat_delete() 910 | { 911 | global $wpdb, $hermit_cat_name, $hermit_table_name; 912 | 913 | $cat_id = $this->post('id'); 914 | if($cat_id == 1)return false; 915 | $result = $wpdb->get_results($wpdb->prepare("SELECT id FROM `$hermit_table_name` WHERE song_cat = %d", $cat_id)); 916 | for ($i = 0; $i < count($result); $i++) { 917 | $wpdb->update($hermit_table_name, array( 918 | 'song_cat' => 1 919 | ), array( 920 | 'id' => $result[$i]->id 921 | ), array( 922 | '%d', 923 | ), array( 924 | '%d' 925 | )); 926 | } 927 | $wpdb->delete($hermit_cat_name, array( 928 | 'id' => $cat_id 929 | )); 930 | 931 | return true; 932 | } 933 | 934 | /** 935 | * 升级本地分类 936 | */ 937 | private function cat_updata() 938 | { 939 | global $wpdb, $hermit_cat_name; 940 | 941 | $id = $this->post('id'); 942 | $title = stripslashes($this->post('title')); 943 | 944 | $wpdb->update($hermit_cat_name, compact('title'), array( 945 | 'id' => $id 946 | ), array( 947 | '%s' 948 | ), array( 949 | '%d' 950 | )); 951 | 952 | return compact('id', 'title'); 953 | } 954 | 955 | /** 956 | * 本地音乐数量 957 | * 音乐库分类 958 | * 959 | * @param null $catid 960 | * 961 | * @return mixed 962 | */ 963 | private function music_count($catid = null) 964 | { 965 | global $wpdb, $hermit_table_name; 966 | 967 | if ($catid) { 968 | $query_str = "SELECT COUNT(id) AS count FROM {$hermit_table_name} WHERE song_cat = '{$catid}'"; 969 | } else { 970 | $query_str = "SELECT COUNT(id) AS count FROM {$hermit_table_name}"; 971 | } 972 | 973 | $music_count = $wpdb->get_var($query_str); 974 | 975 | return $music_count; 976 | } 977 | 978 | private function _css($css_str) 979 | { 980 | $css_arr = explode(',', $css_str); 981 | 982 | if ($this->settings("assetsPublicCDN") && !is_admin()) { 983 | $hermitAssetsUrl = 'https://cdn.jsdelivr.net/gh/moeplayer/hermit-x@' . HERMIT_VERSION; 984 | } else { 985 | $hermitAssetsUrl = HERMIT_URL; 986 | } 987 | 988 | foreach ($css_arr as $key => $val) { 989 | $css_path = sprintf('%s/assets/css/%s.css', $hermitAssetsUrl, $val); 990 | wp_enqueue_style($val, $css_path, false, HERMIT_VERSION); 991 | } 992 | } 993 | 994 | private function _libjs($js_str, $js_place = false) 995 | { 996 | $js_arr = explode(',', $js_str); 997 | 998 | if ($this->settings("assetsPublicCDN") && !is_admin()) { 999 | $hermitAssetsUrl = 'https://cdn.jsdelivr.net/gh/moeplayer/hermit-x@' . HERMIT_VERSION; 1000 | } else { 1001 | $hermitAssetsUrl = HERMIT_URL; 1002 | } 1003 | 1004 | foreach ($js_arr as $key => $val) { 1005 | $js_path = sprintf('%s/assets/js/lib/%s.js', $hermitAssetsUrl, $val); 1006 | wp_enqueue_script($val, $js_path, false, HERMIT_VERSION, $js_place); 1007 | } 1008 | } 1009 | 1010 | private function _js($js_str, $js_place = false) 1011 | { 1012 | $js_arr = explode(',', $js_str); 1013 | 1014 | if ($this->settings("assetsPublicCDN") && !is_admin()) { 1015 | $hermitAssetsUrl = 'https://cdn.jsdelivr.net/gh/moeplayer/hermit-x@' . HERMIT_VERSION; 1016 | } else { 1017 | $hermitAssetsUrl = HERMIT_URL; 1018 | } 1019 | 1020 | foreach ($js_arr as $key => $val) { 1021 | $js_path = sprintf('%s/assets/js/%s.js', $hermitAssetsUrl, $val); 1022 | wp_enqueue_script($val, $js_path, false, HERMIT_VERSION, $js_place); 1023 | } 1024 | } 1025 | 1026 | private function post($key) 1027 | { 1028 | $key = $_POST[$key]; 1029 | 1030 | return $key; 1031 | } 1032 | 1033 | private function get($key) 1034 | { 1035 | $key = esc_attr(esc_html($_GET[$key])); 1036 | 1037 | return $key; 1038 | } 1039 | 1040 | private function error_response($code, $error_message) 1041 | { 1042 | if ($code == 404) { 1043 | header('HTTP/1.1 404 Not Found'); 1044 | } elseif ($code == 301) { 1045 | header('HTTP/1.1 301 Moved Permanently'); 1046 | } else { 1047 | header('HTTP/1.0 500 Internal Server Error'); 1048 | } 1049 | header('Content-Type: text/plain;charset=UTF-8'); 1050 | echo $error_message; 1051 | exit; 1052 | } 1053 | 1054 | private function success_response($result) 1055 | { 1056 | header('HTTP/1.1 200 OK'); 1057 | header('Content-type: application/json;charset=UTF-8'); 1058 | echo json_encode($result); 1059 | exit; 1060 | } 1061 | 1062 | public function aplayer_init() 1063 | { 1064 | if (!$this->settings('debug')) { 1065 | wp_localize_script('hermit-load.min', 'HermitX', array( 1066 | 'ajaxurl' => admin_url('admin-ajax.php'), 1067 | 'version' => HERMIT_VERSION, 1068 | )); 1069 | } else { 1070 | wp_localize_script('hermit-load', 'HermitX', array( 1071 | 'ajaxurl' => admin_url('admin-ajax.php'), 1072 | 'version' => HERMIT_VERSION, 1073 | )); 1074 | } 1075 | } 1076 | 1077 | /** 1078 | * 加载 Gutenberg 区块 1079 | */ 1080 | public function hermitx_editor_assets() 1081 | { 1082 | wp_enqueue_script( 1083 | 'hermitx-block-js', 1084 | HERMIT_URL . '/assets/js/blocks.build.js', 1085 | array('wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor'), 1086 | true 1087 | ); 1088 | } 1089 | } 1090 | --------------------------------------------------------------------------------