// ==UserScript==
// @name Medium傻瓜式一键解锁(可配置多源)bypass Medium
// @namespace https://www.deviantart.com/yuumei
// @version 1.2
// @description 在Medium白嫖浏览付费文章,支持多个解锁源。Support for viewing paid articles for medium.com
// @author mibboy
// @license GPLv3
// @icon https://i.imgur.com/Hs7AiY2.png
// @match *://medium.com/*
// @match *://*.medium.com/*
// @grant GM_getValue
// @grant GM_setValue
// @downloadURL none
// ==/UserScript==
(function() {
'use strict';
// 默认解锁源
const DEFAULT_SOURCES = [
{name: 'Freedium', url: 'freedium.cfd', enabled: true},
{name: 'ReadMedium', url: 'readmedium.com', enabled: false},
{name: 'Scribe', url: 'scribe.rip', enabled: false}
];
// 获取保存的按钮位置
function getButtonPosition() {
return GM_getValue('buttonPosition', {right: '20px', bottom: '20px'});
}
// 保存按钮位置
function saveButtonPosition(position) {
GM_setValue('buttonPosition', position);
}
// 获取保存的解锁源
function getSources() {
return GM_getValue('unlockerSources', DEFAULT_SOURCES);
}
// 保存解锁源
function saveSources(sources) {
GM_setValue('unlockerSources', sources);
}
// 创建设置面板
function createSettingsPanel() {
const panel = document.createElement('div');
panel.id = 'medium-unlock-settings';
panel.innerHTML = `
`;
document.body.appendChild(panel);
// 添加事件监听
document.getElementById('add-source-btn').addEventListener('click', addNewSource);
document.getElementById('close-settings-btn').addEventListener('click', closeSettings);
document.getElementById('save-settings-btn').addEventListener('click', saveSettings);
}
// 添加新源
function addNewSource() {
const nameInput = document.getElementById('new-source-name');
const urlInput = document.getElementById('new-source-url');
if(nameInput.value && urlInput.value) {
const sources = getSources();
sources.push({
name: nameInput.value,
url: urlInput.value,
enabled: true
});
updateSourcesList(sources);
nameInput.value = '';
urlInput.value = '';
}
}
// 关闭设置
function closeSettings() {
const panel = document.getElementById('settings-panel');
if(panel) panel.style.display = 'none';
}
// 保存设置
function saveSettings() {
const sources = [];
document.querySelectorAll('.source-item').forEach(item => {
sources.push({
name: item.querySelector('.source-name').textContent,
url: item.querySelector('.source-url').textContent,
enabled: item.querySelector('.source-enabled').checked
});
});
saveSources(sources);
closeSettings();
updateUnlockButton();
}
// 删除源
function deleteSource(index) {
const sources = getSources();
sources.splice(index, 1);
updateSourcesList(sources);
}
// 更新源列表显示
function updateSourcesList(sources) {
const list = document.getElementById('sources-list');
list.innerHTML = sources.map((source, index) => `
${source.name}
${source.url}
`).join('');
}
// 创建可拖动的解锁按钮
function createUnlockButton() {
const sources = getSources().filter(s => s.enabled);
if(sources.length === 0) return;
const position = getButtonPosition();
const button = document.createElement('div');
button.innerHTML = `
`;
document.body.appendChild(button);
// 添加拖动功能
const unlockButton = document.getElementById('unlock-button');
makeDraggable(unlockButton);
// 添加设置按钮事件
unlockButton.querySelector('.settings-trigger').addEventListener('click', (e) => {
e.stopPropagation(); // 防止触发拖动
document.getElementById('settings-panel').style.display = 'block';
updateSourcesList(getSources());
});
// 添加解锁按钮事件
unlockButton.querySelectorAll('.unlock-option').forEach((option, index) => {
option.addEventListener('click', (e) => {
e.stopPropagation(); // 防止触发拖动
const currentUrl = window.location.href;
const unlockUrl = 'https://' + sources[index].url + '/' + currentUrl;
window.open(unlockUrl, '_blank');
});
option.addEventListener('mouseover', function() {
this.style.transform = 'scale(1.05)';
this.style.background = '#147811';
});
option.addEventListener('mouseout', function() {
this.style.transform = 'scale(1)';
this.style.background = '#1a8917';
});
});
}
// 使元素可拖动
function makeDraggable(element) {
let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
element.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
const newTop = element.offsetTop - pos2;
const newLeft = element.offsetLeft - pos1;
// 确保按钮不会超出屏幕
if (newTop >= 0 && newTop <= window.innerHeight - element.offsetHeight) {
element.style.top = newTop + "px";
}
if (newLeft >= 0 && newLeft <= window.innerWidth - element.offsetWidth) {
element.style.left = newLeft + "px";
}
}
function closeDragElement() {
document.onmouseup = null;
document.onmousemove = null;
// 保存最终位置
saveButtonPosition({
right: element.style.right,
bottom: element.style.bottom
});
}
}
// 更新解锁按钮
function updateUnlockButton() {
const oldButton = document.getElementById('unlock-button');
if(oldButton) oldButton.remove();
createUnlockButton();
}
// 检查是否为Medium文章页面
function isMediumArticle() {
return document.querySelector('article') !== null;
}
// 初始化
function init() {
if(isMediumArticle()) {
if(!document.getElementById('medium-unlock-settings')) {
createSettingsPanel();
}
if(!document.getElementById('unlock-button')) {
createUnlockButton();
}
}
}
// 页面加载完成后执行
if(document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
// 处理动态加载的页面
let lastUrl = location.href;
new MutationObserver(() => {
const url = location.href;
if (url !== lastUrl) {
lastUrl = url;
setTimeout(init, 1000);
}
}).observe(document, {subtree: true, childList: true});
})();