// ==UserScript==
// @name haijiao-vip: 海角社区 解锁收费视频,VIP,去广告
// @namespace https://github.com/sex4096/haijiao_vip
// @version 1.0.5
// @author forgetme8
// @description 解锁 海角社区(haijiao.com) 收费视频,VIP,并去除网站广告, TG频道:@svip_nav.本插件完全免费,请注意甄别,避免上当受骗.
// @homepage https://github.com/sex4096/haijiao_vip#readme
// @supportURL https://github.com/sex4096/haijiao_vip/issue
// @run-at document-idle
// @match https://www.haijiao.com/*
// @match https://haijiao.com/*
// @license MIT
// @connect cdn.jsdelivr.net
// @require https://cdn.jsdelivr.net/npm/[email protected]/umd/react.production.min.js
// @require https://cdn.jsdelivr.net/npm/[email protected]/umd/react-dom.production.min.js
// @require https://cdn.jsdelivr.net/npm/dayjs@1/dayjs.min.js
// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/antd.min.js
// @require https://cdn.jsdelivr.net/npm/@ant-design/[email protected]/dist/index.umd.min.js
// ==/UserScript==
(function (React$1, ReactDOM, antd, icons) {
"use strict";
function _interopDefaultLegacy(e) {
return e && typeof e === "object" && "default" in e ? e : { default: e };
}
var React__default = /*#__PURE__*/ _interopDefaultLegacy(React$1);
var ReactDOM__default = /*#__PURE__*/ _interopDefaultLegacy(ReactDOM);
var __webpack_require__ = undefined;
var VUE = undefined;
var STORE = undefined;
var AXIOS = undefined;
var callback = undefined;
function initHookWebpack(initialed) {
callback = initialed;
let originCall = Function.prototype.call;
Function.prototype.call = function () {
for (
var _len = arguments.length, args = new Array(_len), _key = 0;
_key < _len;
_key++
) {
args[_key] = arguments[_key];
}
const result = originCall.apply(this, args);
if (
args.length === 4 &&
args[1] &&
args[1].exports &&
args[0] === args[2] &&
__webpack_require__ === undefined
) {
__webpack_require__ = args[3];
Function.prototype.call = originCall;
importModules();
}
return result;
};
}
function importModules() {
VUE = __webpack_require__("2b0e").default;
STORE = __webpack_require__("4360").a;
AXIOS = __webpack_require__("bc3a");
AXIOS = getObject(AXIOS);
AXIOS = AXIOS.a;
callback(VUE, STORE, AXIOS);
}
function getObject(module) {
const t =
module && module.__esModule
? function () {
return module.default;
}
: function () {
return module;
};
defineObject(t, "a", t);
return t;
}
function defineObject(module, key, value) {
Object.prototype.hasOwnProperty.call(module, key) ||
Object.defineProperty(module, key, {
enumerable: true,
get: value,
});
}
/**
* 加载模块
* @param module
*/
function getModule(module) {
if (!__webpack_require__) return null;
return __webpack_require__(module);
}
const Settings = (_ref) => {
let { initialSettings, onFormInstanceReady } = _ref;
const [form] = antd.Form.useForm();
React$1.useEffect(() => {
onFormInstanceReady(form);
}, []);
return /*#__PURE__*/ React.createElement(
React.Fragment,
null,
/*#__PURE__*/ React.createElement(
antd.Form,
{
form: form,
name: "settings",
labelAlign: "right",
labelCol: {
span: 8,
},
wrapperCol: {
span: 16,
},
initialValues: initialSettings,
},
/*#__PURE__*/ React.createElement(
antd.Form.Item,
{
label: "\u53BB\u5E7F\u544A",
},
/*#__PURE__*/ React.createElement(
antd.Form.Item,
{
name: "removeAds",
noStyle: true,
},
/*#__PURE__*/ React.createElement(antd.Switch, null)
),
/*#__PURE__*/ React.createElement(
"span",
{
style: {
marginLeft: 10,
},
},
"\u53BB\u9664\u7F51\u7AD9\u5E7F\u544A"
)
),
/*#__PURE__*/ React.createElement(
antd.Form.Item,
{
label: "\u5C4F\u853D\u7F6E\u9876",
},
/*#__PURE__*/ React.createElement(
antd.Form.Item,
{
name: "removeTops",
noStyle: true,
},
/*#__PURE__*/ React.createElement(antd.Switch, null)
),
/*#__PURE__*/ React.createElement(
"span",
{
style: {
marginLeft: 10,
},
},
"\u5C4F\u853D\u5168\u5C40\u7F6E\u9876\u5E16"
)
),
/*#__PURE__*/ React.createElement(
antd.Form.Item,
{
label: "\u67E5\u770B\u5C01\u7981\u7528\u6237",
},
/*#__PURE__*/ React.createElement(
antd.Form.Item,
{
name: "viewBanUser",
noStyle: true,
},
/*#__PURE__*/ React.createElement(antd.Switch, null)
),
/*#__PURE__*/ React.createElement(
"span",
{
style: {
marginLeft: 10,
},
},
"\u67E5\u770B\u88AB\u5C01\u7981\u7684\u7528\u6237\u4FE1\u606F"
)
),
/*#__PURE__*/ React.createElement(
antd.Form.Item,
{
label: "\u89E3\u9501VIP",
},
/*#__PURE__*/ React.createElement(
antd.Form.Item,
{
name: "unlockVip",
noStyle: true,
},
/*#__PURE__*/ React.createElement(antd.Switch, null)
),
/*#__PURE__*/ React.createElement(
"span",
{
style: {
marginLeft: 10,
},
},
"\u53EF\u89C2\u770Bvip\u533A\u7684\u5E16\u5B50\u53CA\u89C6\u9891"
)
),
/*#__PURE__*/ React.createElement(
antd.Form.Item,
{
label: "\u89E3\u9501\u6536\u8D39\u89C6\u9891",
},
/*#__PURE__*/ React.createElement(
antd.Form.Item,
{
name: "unlockBuy",
noStyle: true,
},
/*#__PURE__*/ React.createElement(antd.Switch, null)
),
/*#__PURE__*/ React.createElement(
"span",
{
style: {
marginLeft: 10,
},
},
"\u53EF\u89C2\u770B\u9700\u8981\u8D2D\u4E70\u7684\u89C6\u9891"
)
),
/*#__PURE__*/ React.createElement(
antd.Form.Item,
{
label: "\u670D\u52A1\u5730\u5740",
},
/*#__PURE__*/ React.createElement(
antd.Form.Item,
{
name: "host",
noStyle: true,
rules: [
{
required: true,
message: "请输入服务器地址",
},
],
},
/*#__PURE__*/ React.createElement(antd.Input, null)
),
/*#__PURE__*/ React.createElement(
"div",
{
style: {
color: "red",
marginTop: 5,
},
},
"\u670D\u52A1\u5668\u5730\u5740\u4E0D\u5B9A\u65F6\u66F4\u6362"
),
/*#__PURE__*/ React.createElement(
"div",
null,
"\u8BF7\u8BA2\u9605TG\u9891\u9053:@svip_nav\u83B7\u53D6\u6700\u65B0\u5730\u5740"
)
)
)
);
};
class PluginStore {
static get(key, defaultValue) {
const value = localStorage.getItem(key);
if (value === null) {
return defaultValue;
}
if (typeof defaultValue === "number") {
return parseInt(value);
}
if (typeof defaultValue === "boolean") {
return value === "true";
}
return value;
}
static set(key, value) {
localStorage.setItem(key, value.toString());
}
}
const App = () => {
const [isModalOpen, setIsModalOpen] = React$1.useState(false);
const [formInstance, setFormInstance] = React$1.useState();
const showModal = () => {
setIsModalOpen(true);
};
const handleOk = async () => {
const values = await formInstance?.validateFields();
onCreate(values);
setIsModalOpen(false);
};
const handleCancel = () => {
setIsModalOpen(false);
};
const onCreate = (values) => {
console.log("Received values of form: ", values);
PluginStore.set("removeAds", values.removeAds);
PluginStore.set("removeTops", values.removeTops);
PluginStore.set("unlockVip", values.unlockVip);
PluginStore.set("unlockBuy", values.unlockBuy);
PluginStore.set("viewBanUser", values.viewBanUser);
PluginStore.set("host", values.host);
};
return /*#__PURE__*/ React__default["default"].createElement(
React__default["default"].Fragment,
null,
/*#__PURE__*/ React__default["default"].createElement(antd.FloatButton, {
type: "primary",
tooltip: "\u6D77\u89D2VIP\u8BBE\u7F6E",
style: {
left: 16,
},
icon: /*#__PURE__*/ React__default["default"].createElement(
icons.SettingOutlined,
null
),
onClick: showModal,
}),
/*#__PURE__*/ React__default["default"].createElement(
antd.Modal,
{
title: "\u8BBE\u7F6E",
open: isModalOpen,
onOk: handleOk,
onCancel: handleCancel,
destroyOnClose: true,
okButtonProps: {
autoFocus: true,
},
},
/*#__PURE__*/ React__default["default"].createElement(Settings, {
initialSettings: {
removeAds: PluginStore.get("removeAds", true),
removeTops: PluginStore.get("removeTops", true),
viewBanUser: PluginStore.get("viewBanUser", true),
unlockVip: PluginStore.get("unlockVip", true),
unlockBuy: PluginStore.get("unlockBuy", true),
host: PluginStore.get("host", "https://haijiao.ku-cloud.com"),
},
onFormInstanceReady: (instance) => {
setFormInstance(instance);
},
})
)
);
};
/**
* 自定义拦截器
*/
class Interceptor {
// axios模块
constructor(axios) {
this.axios = axios;
}
/**
* 初始化请求拦截器
*/
initRequestInterceptor() {
this.axios.interceptors.request.use(this.requestInterceptor.bind(this));
}
/**
* 初始化返回请求拦截器
*/
initResponseInterceptor() {
if (this.axios.interceptors.response.handlers.length != 1) {
return;
}
// 因为返回处理会处理掉config,而我们需要config中的url,所以需要在返回处理之前处理
if (this.axios.interceptors.response.handlers?.[0].fulfilled) {
const origin = this.axios.interceptors.response.handlers?.[0].fulfilled;
this.axios.interceptors.response.handlers[0].fulfilled = async (
response
) => {
const data = await origin(response);
response = {
data: data,
config: response.config,
};
return response;
};
}
this.axios.interceptors.response.use(
this.responseDecodeInterceptor.bind(this)
);
this.axios.interceptors.response.use(this.responseInterceptor.bind(this));
this.axios.interceptors.response.use(
this.responseEncodeInterceptor.bind(this)
);
}
/**
* 请求拦截器
* @param request
* @returns
*/
async requestInterceptor(request) {
request = await this.requestUnlockBuyInterceptor(request);
request = await this.requestUnlockBanUserInterceptor(request);
request = await this.requestSearchInterceptor(request);
return request;
}
/**
* 解锁购买
* @param request
* @returns
*/
async requestUnlockBuyInterceptor(request) {
if (
PluginStore.get("unlockBuy", false) === true &&
PluginStore.get("host", "").length > 0
) {
if (
/\/api\/attachment/g.test(request.url) ||
/topic\/\d+/g.test(request.url)
) {
console.log("转发请求", request.url, request);
var host = PluginStore.get("host", "");
request.baseURL = host;
request.crossDomain = true;
}
}
return request;
}
/**
* 查看被ban的用户信息
* @param request
*/
async requestUnlockBanUserInterceptor(request) {
if (
PluginStore.get("unlockBanUser", true) === true &&
PluginStore.get("host", "").length > 0
) {
if (
/\/api\/user\/info\/\d+/g.test(request.url) ||
/\/api\/user\/news\/other_news_list/g.test(request.url) ||
(/\/api\/topic\/node\/topics/g.test(request.url) &&
request.url.includes("userId"))
) {
console.log("查看被ban的用户信息", request.url);
var host = PluginStore.get("host", "");
request.baseURL = host;
request.crossDomain = true;
}
}
return request;
}
/**
* 解锁搜索功能
* @param request
*/
async requestSearchInterceptor(request) {
if (
PluginStore.get("unlockSearch", true) === true &&
PluginStore.get("host", "").length > 0
) {
if (/\/api\/user\/search/g.test(request.url)) {
console.log("搜索", request.url);
var host = PluginStore.get("host", "");
request.baseURL = host;
request.crossDomain = true;
}
}
return request;
}
/**
* 对返回数据进行解码
* @param response
*/
async responseDecodeInterceptor(response) {
if (response.data.status === 200) {
const origin_response = JSON.parse(JSON.stringify(response.data.data));
var enc_data = response.data.data.data;
if (enc_data && typeof enc_data === "string" && enc_data.length > 0) {
const Base64 = getModule("e762").a;
enc_data = JSON.parse(
Base64.decode(Base64.decode(Base64.decode(enc_data)))
);
}
response = {
item: enc_data,
url: response.config.url,
mobile: true,
origin_response: origin_response,
};
} else {
// 克隆一个原始请求
const origin_response = JSON.parse(JSON.stringify(response.data));
const item = JSON.parse(JSON.stringify(response.data.data));
response = {
item: item,
url: response.config.url,
mobile: false,
origin_response: origin_response,
};
}
return response;
}
/**
* 对reponse重新编码
* @param response
* @returns
*/
async responseEncodeInterceptor(response) {
if (response.mobile === true) {
var dec = response.item;
if (response.origin_response.isEncrypted === true) {
const Base64 = getModule("e762").a;
dec = Base64.encode(
Base64.encode(Base64.encode(JSON.stringify(response.item)))
);
}
return {
data: {
...response.origin_response,
data: dec,
},
};
} else {
return {
...response.origin_response,
data: response.item,
};
}
}
async responseInterceptor(response) {
const url = response.url.toLowerCase();
var item = response.item;
console.log("拦截器返回数据", url, item);
if (
/^\/api\/topic\/\d+/g.test(url) &&
PluginStore.get("unlockVip", true) === true
) {
item = await this.fixTopic(item);
}
// 去广告
else if (
/banner\/banner_list/g.test(url) &&
PluginStore.get("removeAds", true) === true
) {
item = await this.fixAds(item);
}
// 屏蔽置顶帖
else if (
/^\/api\/topic\/global\/topics/g.test(url) &&
PluginStore.get("removeTops", true) === true
) {
item = await this.fixTops(item);
}
response.item = item;
return response;
}
/**
* 修复帖子内容
* @param {*} data
* @returns
*/
async fixTopic(data) {
console.log("修复帖子内容", data);
if (data.node?.vipLimit > 0) {
data.node.vipLimit = 0;
}
var content = data.content;
if (content && !content.startsWith("<html><head></head><body>")) {
// 删除掉[]标签
content = content.replace(/\[视频\]/g, "");
content = content.replace(/\[图片\]/g, "");
content = content.replace(/此处内容售价\d+金币.*请购买后查看./g, "");
content = content.replace(/\[sell.*\/sell]/g, "");
data.attachments?.forEach((attachment) => {
var hasImage,
hasVideo = false;
// 处理图片
if (attachment.category === "images" && attachment.remoteUrl) {
content =
content += `<p><img src="${attachment.remoteUrl}" data-id="${attachment.id}"/>`;
hasImage = true;
}
if (hasImage === true) {
content = `<p>${content}</p>`;
}
if (attachment.category === "video") {
// if (attachment.remoteUrl) {
hasVideo = true;
content += `<p><video src="${attachment.remoteUrl}" data-id="${attachment.id}"></video></p>`;
// } else {
// console.log("视频链接为空", attachment);
// content += `<p><div style="color:red;text-decoration:line-through;">${attachment.error}</div></p>`;
// }
}
if (hasVideo === true) {
content = `<p>${content}</p>`;
}
});
content = `<html><head></head><body>${content}</body></html>`;
}
data.content = content;
return data;
}
/**
* 去广告
* @param data
*/
async fixAds(data) {
return null;
}
async fixTops(data) {
return [];
}
}
function addStyle() {
let script = document.createElement("link");
script.setAttribute("rel", "stylesheet");
script.setAttribute("type", "text/css");
script.href = "https://cdn.jsdelivr.net/npm/[email protected]/dist/reset.min.css";
document.documentElement.appendChild(script);
}
function addAnalytics() {
const script = document.createElement("script");
script.src = "https://www.googletagmanager.com/gtag/js?id=G-NQ08DH5N3T";
script.async = true;
document.head.appendChild(script);
const script2 = document.createElement("script");
script2.innerHTML = `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-NQ08DH5N3T');
`;
document.head.appendChild(script2);
}
function initialed(vue, store, axios) {
const interceptor = new Interceptor(axios);
interceptor.initRequestInterceptor();
interceptor.initResponseInterceptor();
}
function initSetting() {
const myButton = /*#__PURE__*/ React__default["default"].createElement(
App,
null
);
const pluginDiv = document.createElement("div");
pluginDiv.id = "haijiao-vip-plugin";
document.body.appendChild(pluginDiv);
ReactDOM__default["default"].render(myButton, pluginDiv);
}
sessionStorage.setItem("pageOpen", "1");
addAnalytics();
addStyle();
initSetting();
initHookWebpack(initialed);
})(React, ReactDOM, antd, icons);