MoreRSS

site iconGorpeln Chen修改

致力于成为一名架构师的的iOS工程师。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

Gorpeln Chen的 RSS 预览

博客新添的宝藏小功能

2024-12-21 08:00:00

1. 侧栏倒计时

不仅能够精准显示距离特定节日的剩余时间,满足用户对重要节庆的期待与关注,还能直观展示今日、本周、本月乃至本年已悄然流逝的时间比例,帮助用户实时洞察时间的流转,让每一刻都能在时间的刻度中清晰呈现,实现对时间的高效感知与管理。

效果
20241221151857321

方法
1、 countdown.html

<div class="countdownNav" id="countdownNav">
    <div class="card-widget card-countdown">
        <div class="item-headline"><i></i><span></span></div>
        <div class="item-content">
            <div class="cd-count-left">
                <span class="cd-text">距离</span>
                <span class="cd-name" id="eventName">节日</span>
                <span class="cd-time" id="daysUntil">000</span>
                <span class="cd-date" id="eventDate">2015-08-23</span>
            </div>
            <div id="countRight" class="cd-count-right">
                <div id="countRight" class="cd-count-right">
                    <div class="cd-count-item">
                        <div class="cd-item-name">今日</div>
                        <div class="cd-item-progress"></div>
                    </div>
                    <div class="cd-count-item">
                        <div class="cd-item-name">本周</div>
                        <div class="cd-item-progress"></div>
                    </div>
                    <div class="cd-count-item">
                        <div class="cd-item-name">本月</div>
                        <div class="cd-item-progress"></div>
                    </div>
                    <div class="cd-count-item">
                        <div class="cd-item-name">本年</div>
                        <div class="cd-item-progress"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

2、 countdown.js

const CountdownTimer = (() => {
    const config = {
        targetDate: "2025-10-01",
        targetName: "国庆",
        units: {
            day: { text: "今日", unit: "小时" },
            week: { text: "本周", unit: "天" },
            month: { text: "本月", unit: "天" },
            year: { text: "本年", unit: "天" }
        }
    };

    const calculators = {
        day: () => {
            const hours = new Date().getHours();
            return {
                remaining: 24 - hours,
                percentage: (hours / 24) * 100
            };
        },
        week: () => {
            const day = new Date().getDay();
            const passed = day === 0 ? 6 : day - 1;
            return {
                remaining: 6 - passed,
                percentage: ((passed + 1) / 7) * 100
            };
        },
        month: () => {
            const now = new Date();
            const total = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate();
            const passed = now.getDate() - 1;
            return {
                remaining: total - passed,
                percentage: (passed / total) * 100
            };
        },
        year: () => {
            const now = new Date();
            const start = new Date(now.getFullYear(), 0, 1);
            const total = 365 + (now.getFullYear() % 4 === 0 ? 1 : 0);
            const passed = Math.floor((now - start) / 86400000);
            return {
                remaining: total - passed,
                percentage: (passed / total) * 100
            };
        }
    };

    function updateCountdown() {
        const elements = ['eventName', 'eventDate', 'daysUntil', 'countRight']
           .map(id => document.getElementById(id));

        if (elements.some(el => !el)) return;

        const [eventName, eventDate, daysUntil, countRight] = elements;
        const now = new Date();
        const target = new Date(config.targetDate);

        eventName.textContent = config.targetName;
        eventDate.textContent = config.targetDate;
        daysUntil.textContent = Math.round((target - now.setHours(0, 0, 0, 0)) / 86400000);

        countRight.innerHTML = Object.entries(config.units)
           .map(([key, { text, unit }]) => {
                const { remaining, percentage } = calculators[key]();
                return `
                    <div class="cd-count-item">
                        <div class="cd-item-name">${text}</div>
                        <div class="cd-item-progress">
                            <div class="cd-progress-bar" style="width: ${percentage}%; opacity: ${percentage}"></div>
                            <span class="cd-percentage ${percentage >= 46 ? 'cd-many' : ''}">${percentage.toFixed(2)}%</span>
                            <span class="cd-remaining ${percentage >= 60 ? 'cd-many' : ''}">
                                <span class="cd-tip">还剩</span>${remaining}<span class="cd-tip">${unit}</span>
                            </span>
                        </div>
                    </div>
                `;
            }).join('');
    }

    let timer;
    const start = () => {
        updateCountdown();
        timer = setInterval(updateCountdown, 600000);
    };

    ['pjax:complete', 'DOMContentLoaded'].forEach(event => document.addEventListener(event, start));
    document.addEventListener('pjax:send', () => timer && clearInterval(timer));

    return { start, stop: () => timer && clearInterval(timer) };
})();

3、 style.css

/*倒计时*/
.countdownNav {
    margin-top: 1em;
    background-color: var(--box-color-light);
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    overflow: hidden;
    width: 100%;
}
.card-countdown {
    margin: 0.75em 1.5em;
}

.card-countdown .item-content {
    display: flex;
}

.cd-count-left {
    position: relative;
    display: flex;
    flex-direction: column;
    margin-right: 0.8rem;
    line-height: 1.5;
    align-items: center;
    justify-content: center;
}

.cd-count-left .cd-text {
    font-size: 14px;
}

.cd-count-left .cd-name {
    font-weight: bold;
    font-size: 18px;
}

.cd-count-left .cd-time {
    font-size: 30px;
    font-weight: bold;
    color: #dad9e6;
}

.cd-count-left .cd-date {
    font-size: 12px;
    opacity: 0.6;
}

.cd-count-left::after {
    content: "";
    position: absolute;
    right: -0.8rem;
    width: 2px;
    height: 80%;
    background-color: #dad9e6;
    opacity: 0.5;
}

.cd-count-right {
    flex: 1;
    margin-left: .8rem;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}

.cd-count-item {
    display: flex;
    flex-direction: row;
    align-items: center;
    height: 24px;
}

.cd-item-name {
    font-size: 14px;
    margin-right: 0.8rem;
    white-space: nowrap;
}

.cd-item-progress {
    position: relative;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    height: 100%;
    width: 100%;
    border-radius: 8px;
    background-color: var(--background-color-light);
    overflow: hidden;
}

.cd-progress-bar {
    height: 100%;
    border-radius: 8px;
    background-color: #dad9e6;
}

.cd-percentage,
.cd-remaining {
    position: absolute;
    font-size: 12px;
    margin: 0 6px;
    transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out;
}

.cd-many {
    color: #fff;
}

.cd-remaining {
    opacity: 0;
    transform: translateX(10px);
}

.card-countdown .item-content:hover .cd-remaining {
    transform: translateX(0);
    opacity: 1;
}

.card-countdown .item-content:hover .cd-percentage {
    transform: translateX(-10px);
    opacity: 0;
}

2. 彩带、樱花背景

效果
20241221151857322

方法

<!--  樱花背景 -->
<script type="text/javascript" src="/assets/js/sakura.js"></script>
<!--  丝带背景 -->
<script size="150" alpha="0.3" zindex="-2" src="/assets/js/ribbon.min.js"></script>

注意:将文件下载到自己博客使用
https://gorpeln.top/assets/js/sakura.js
https://gorpeln.top/assets/js/ribbon.min.js

3. 春节灯笼

效果
20241221151857323方法

<link rel="stylesheet" type="text/css" href="../assets/css/deng.css">

注意:将文件下载到自己博客使用
https://gorpeln.top/assets/css/deng.css

html代码

<!-- 春节灯笼 -->
<div style="display:none;" id="lanterns">
    <div class="deng-box">
        <div class="deng">
            <div class="xian"></div>
            <div class="deng-a">
                <div class="deng-b">
                    <div class="deng-t">快乐</div>
                </div>
            </div>
            <div class="shui shui-a">
                <div class="shui-c"></div>
                <div class="shui-b"></div>
            </div>
        </div>
    </div>
    <div class="deng-box1">
        <div class="deng">
            <div class="xian"></div>
            <div class="deng-a">
                <div class="deng-b">
                    <div class="deng-t">新春</div>
                </div>
            </div>
            <div class="shui shui-a">
                <div class="shui-c"></div>
                <div class="shui-b"></div>
            </div>
        </div>
    </div>
</div>
<!-- 春节灯笼 -->
<script>
document.addEventListener("DOMContentLoaded", function() {
    // 获取当前日期
    var currentDate = new Date();
    
    // 定义开始日期和结束日期
    var startDate = new Date('2025-01-22');//腊月廿三
    var endDate = new Date('2025-02-12');//正月十五

    // 获取 div 元素
    var specialDiv = document.getElementById('lanterns');

    // 检查当前日期是否在指定的日期范围内
    if (currentDate >= startDate && currentDate <= endDate) {
        // 如果在范围内,则显示 div
        specialDiv.style.display = 'block';
    } else {
        // 否则,隐藏 div
        specialDiv.style.display = 'none';
    }
});
</script>

4、 其他

  1. 点击 RSS ,会有猫叫声
  2. 头像的闪动光效

友链自动监测

2024-11-08 08:00:00

前言

管理友链时采取手动点击检验的方式,随着时间的推移,友链数量逐渐增加,这一做法显然已不再高效。于是就需要写了一项类似API的功能,输出所有友链数据的可达性。

功能概览

  1. github action自动定时检测友链状态,结果输出到page分支下的result.json。
  2. 友链状态展示页面,可以部署到zeabur或者vercel,加速api访问速度。
  3. 为确保兼容性,实现了两种检测方案:
    • 非兼容:使用格式文件动态读取友链内容,实现功能,友链列表自动实时性更新。
    • 兼容:使用TXT存储所有友链信息,兼容性好,适合所有站点,但是添加友链后可能需要手动更新文件。
  4. API访问数据,api包含数据包括可达链接、不可达链接、可达链接数目、不可达链接数目、更新时间戳,其中链接中包含站点名称和地址,便于前端部署。
  5. 测试脚本使用python,使用Request包的get和head两种检测方式检测,尽可能减少误判概率。
  6. 前端采用本地缓存,减少api调用次数,缓存半个小时刷新,不影响实时性。

预览

博客中预览:https://friends.gorpeln.top/

20241108160343641

其他

友链相关的常见问题

定期自动备份又拍云存储

2024-10-05 08:00:00

前言

数据无价,备份无忧。

将其他平台数据备份到不同平台的好处:

  • 增强数据安全性:通过定期备份到GitHub,即使又拍云服务出现问题,你的数据仍然安全。这为你的数据提供了额外的一层保护,尤其是使用国内免费服务的用户。
  • 便于版本管理:GitHub支持Git版本控制系统,这意味着你可以轻松追踪数据的变化历史,这对于需要保存多个版本的数据集或文档非常有用。
  • 自动化操作:使用GitHub Actions,你可以设置自动化的工作流来定期执行备份脚本。这不仅减少了手动操作的需求,还降低了人为错误的风险。
  • 成本效益:对于小规模项目或个人开发者来说,使用GitHub作为备份存储可能比租用额外的云存储空间更经济。特别是当使用GitHub的免费层级时。
  • 易于访问和分享:GitHub上的数据可以通过简单的链接分享给他人,这对于公开数据集或开源项目尤其有益。

预览

又拍云目录: 20241005111856740

github目录: 20241005111856741

操作示例

1. 新增 Workflow YML 文件

upyun_images_sync/.github/workflows/sync-images.yml

name: Sync Images from UpYun to GitHub

on:
  schedule:
    - cron: '0 0 * * 3'  # 每周三凌晨 0 点运行
  workflow_dispatch:  # 允许手动触发

jobs:
  sync-images:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout repository
      uses: actions/checkout@v2

    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.x'

    - name: Install dependencies
      run: |
        pip install gitpython

    - name: Run sync script
      env:
        UPYUN_FTP_HOST: $
        UPYUN_FTP_USER: $
        UPYUN_FTP_PASSWORD: $
        UPYUN_FTP_PATH: $
        LOCAL_DOWNLOAD_PATH: ./tmp
        REPO_PATH: ./repo
        GH_TOKEN: $
        REPO_OWNER: $
        REPO_NAME: $
        BRANCH_NAME: $
      run: |
        python3 sync_images.py

2. 新建 Python 同步脚本

upyun_images_sync/sync_images.py

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

import os
from ftplib import FTP
import git
import shutil

class MyFTP:
    def __init__(self, host, port=21):
        self.host = host
        self.port = port
        self.ftp = FTP()
        self.ftp.encoding = 'utf8'
        self.file_list = []

    def login(self, username, password):
        try:
            self.ftp.connect(self.host, self.port)
            self.ftp.login(username, password)
            print(f"成功登录到 {self.host}")
            print(f"当前工作目录: {self.ftp.pwd()}")
        except Exception as err:
            print(f"FTP 连接或登录失败,错误描述为:{err}")
            sys.exit(1)

    def download_file(self, local_file, remote_file):
        if os.path.exists(local_file):
            print(f"{local_file} 已存在,跳过下载")
            return
        try:
            print(f"下载文件 {remote_file} 到 {local_file}")
            buf_size = 1024
            with open(local_file, 'wb') as file_handler:
                self.ftp.retrbinary(f'RETR {remote_file}', file_handler.write, buf_size)
        except Exception as err:
            print(f"下载文件出错,出现异常:{err}")

    def download_file_tree(self, local_path, remote_path):
        try:
            print(f"尝试切换到远程目录: {remote_path}")
            self.ftp.cwd(remote_path)
            print(f"成功切换到远程目录: {remote_path}")
        except Exception as err:
            print(f"远程目录 {remote_path} 不存在,继续... 具体错误描述为:{err}")
            return

        if not os.path.isdir(local_path):
            os.makedirs(local_path)
            print(f"创建本地目录 {local_path}")

        print(f"当前工作目录: {self.ftp.pwd()}")

        # 列出目录内容
        remote_files = self.ftp.nlst()
        print(f"远程目录内容: {remote_files}")

        for remote_file in remote_files:
            local = os.path.join(local_path, remote_file)
            if remote_file in ['.', '..']:
                continue
            try:
                self.ftp.cwd(remote_file)
                print(f"下载目录:{remote_file}")
                self.download_file_tree(local, os.path.join(remote_path, remote_file))
                self.ftp.cwd("..")
            except Exception:
                print(f"下载文件:{remote_file}")
                self.download_file(local, os.path.join(remote_path, remote_file))

    def close(self):
        print("FTP退出")
        self.ftp.quit()

def sync_to_github(repo_path, branch_name):
    if os.path.exists(repo_path):
        shutil.rmtree(repo_path)
    os.makedirs(repo_path)

    repo_url = f"https://{GH_TOKEN}@github.com/{REPO_OWNER}/{REPO_NAME}.git"
    print(f"克隆仓库: {repo_url}")
    try:
        repo = git.Repo.clone_from(repo_url, repo_path, branch=branch_name)
        print(f"克隆仓库到 {repo_path}")
    except git.exc.GitCommandError as e:
        print(f"克隆仓库失败: {e}")
        return

    images_dir = os.path.join(repo_path, 'images')
    if not os.path.exists(images_dir):
        os.makedirs(images_dir)

    shutil.copytree(LOCAL_DOWNLOAD_PATH, images_dir, dirs_exist_ok=True)
    print(f"复制文件到 {images_dir}")

    repo.git.add(all=True)
    if repo.is_dirty():
        repo.index.commit("Sync images from UpYun")
        origin = repo.remote(name='origin')
        origin.push()
        print("推送更改到 GitHub 仓库")
    else:
        print("没有更改需要提交")

if __name__ == "__main__":
    # 从环境变量中读取配置
    UPYUN_FTP_HOST = os.getenv('UPYUN_FTP_HOST')
    UPYUN_FTP_USER = os.getenv('UPYUN_FTP_USER')
    UPYUN_FTP_PASSWORD = os.getenv('UPYUN_FTP_PASSWORD')
    UPYUN_FTP_PATH = os.getenv('UPYUN_FTP_PATH', '/')
    LOCAL_DOWNLOAD_PATH = os.getenv('LOCAL_DOWNLOAD_PATH', './tmp')
    REPO_PATH = os.getenv('REPO_PATH', './repo')
    GH_TOKEN = os.getenv('GH_TOKEN')
    REPO_OWNER = os.getenv('REPO_OWNER')
    REPO_NAME = os.getenv('REPO_NAME')
    BRANCH_NAME = os.getenv('BRANCH_NAME', 'master')

    # 创建 FTP 对象
    my_ftp = MyFTP(UPYUN_FTP_HOST)
    # 登录 FTP 服务器
    my_ftp.login(UPYUN_FTP_USER, UPYUN_FTP_PASSWORD)
    
    # 下载目录
    my_ftp.download_file_tree(LOCAL_DOWNLOAD_PATH, UPYUN_FTP_PATH)
    
    # 关闭 FTP 连接
    my_ftp.close()

    # 同步到 GitHub
    sync_to_github(REPO_PATH, BRANCH_NAME)

3. 授予 Workflow 读写权限

将本地的项目提交到github,然后设置Workflow 读写权限

20241005111856742

4. 新增 Secrets 变量

在github上设置Secrets 变量

20241005111856743

序号 变量名 释义
1 UPYUN_FTP_HOST 又拍云 FTP 主机地址
2 UPYUN_FTP_USER 又拍云 FTP 用户名
3 UPYUN_FTP_PASSWORD 又拍云 FTP 密码
4 UPYUN_FTP_PATH 又拍云 FTP 路径
5 GH_TOKEN GitHub 个人访问令牌
6 REPO_OWNER 仓库所有者
7 REPO_NAME 仓库名称
8 BRANCH_NAME 分支名称(默认为 master)

变量详解:

  1. UPYUN_FTP_HOST:参考又拍云文档,直接使用v0.ftp.upyun.com就行了
  2. UPYUN_FTP_USER:格式为 operator/bucket,在又拍云 - 云存储 - 选择对应的bucket点击配置 - 存储管理 - 操作员授权 - 自己添加操作用户名和密码,假设你的又拍云云储存bucket的名称为upai-img,自定义的用户名为user,密码为123456,则UPYUN_FTP_USER就是 user/upai-img,如果你看不懂我说的,参考 又拍云视频教程
  3. UPYUN_FTP_PASSWORD:就是上面你自己设置的 123456图片示例
  4. UPYUN_FTP_PATH:直接使用 / (根目录)就行了
  5. GH_TOKEN:选择github的 Settings - 点击右侧列表最下面的 Developer Settings - Personal access tokens - tokens (classic) - Generated new token (classic),Note名字可以随意,Expiration时间选择 no Expiration,下面权限全选了,点击Generated token 就生成了想要的token,记得保存,他只显示一次,示例:abc_123456789pUS123454321WmJkE987654321图片示例
  6. REPO_OWNER:就是你的github的用户名,我在github给这个项目创建仓库为https://github.com/gorpeln/upyun_images_sync,示例:gorpeln
  7. REPO_NAME:仓库链接后面的就是仓库名,示例:upyun_images_sync图片示例
  8. BRANCH_NAME:项目分支名,一般为master/main,示例:master

博客常见问题

2024-09-17 08:00:00

博客目标?

简洁、高效

如何联系博主?

可以通过邮件联系博主,注意将邮件地址中的*替换掉

评论加载不出来?

博客已开启CDN,整体访问速度较快。
但博客评论、公告、实验室等功能采用不同域名访问,可能存在无法访问的情况。
如果可能,请科学上网。或者多次刷新加载(5-6次),就可以正常展示

博客成长记录?

查看博客成长记录

友链相关问题?

查看友链相关问题

博客相关协议?

查看博客相关协议

其他问题?

正在整理中...

防止网站被恶意镜像

2024-08-24 08:00:00

什么是网站镜像?

网站镜像是指在互联网上出现一个与你的网站几乎一模一样的复制品,除了域名不同之外,其它所有内容都完全相同。这包括网站的布局、LOGO、版块结构等。

通常,网站被恶意镜像的情况主要有两种:

  • 完全镜像:这种情况是创建一个与您网站内容完全相同的站点,除了网址不同,其他一切都模仿您的设计和内容。
  • 内容抓取:这种情况常见于博彩网站,它们会恶意抓取您的网页内容,正常浏览时隐藏掉原有内容,显示的却是他们自己的广告。

20240824212126440

在上述例子中,明显属于第一种情况:对方镜像了我的网站布局和结构。这种行为属于灰色 SEO 和黑帽 SEO 手法,目的是为了借助我博客的权重和流量来提升他们自己网站的排名。 20240824212126441

网站被镜像危害

从搜索引擎来讲,会对搜索引擎抓取不利,影响原本网站的正常抓取和识别,可能会导致原网站权重丢失,也有可能带来一定的误伤,搜索引擎会对网站进行识别,如果发现是镜像站,会导致网站被搜索引擎屏蔽,将失去搜索引擎带来的流量(这对个人博客来说是致命的)。

对用户来讲,可能会被镜像网站欺骗,恶意广告插播或欺诈内容造成用户损失。

网站被镜像了怎么办

添加防镜像跳转代码

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>not mirroring</title>
<style>
    .alert-message {
        position: fixed;
        top: 45%;
        left: 50%;
        transform: translate(-50%, -50%);
        background-color: #f8d7da;
        color: #721c24;
        padding: 20px;
        z-index: 10000;
        opacity: 1;
        transition: opacity 3s;
        border-radius:16px;
    }
    .alert-message.fade-out {
        opacity: 0;
    }
</style>
</head>
<body>

<script>
(function () {
    // 定义合法域名列表并Base64编码
    var validDomains = ['Z29ycGVsbi50b3A=']; // gorpeln.top
    var redirectUrl = 'aHR0cHM6Ly9nb3JwZWxuLnRvcA=='; // https://gorpeln.top
    var hostname = document.location.hostname + (document.location.port ? ':' + document.location.port : '');

    function createWatermark(text) {
        var watermarkDiv = document.createElement('div');
        watermarkDiv.style.pointerEvents = 'none';
        watermarkDiv.style.position = 'fixed';
        watermarkDiv.style.top = '0';
        watermarkDiv.style.left = '-5%';
        watermarkDiv.style.width = '110%';
        watermarkDiv.style.height = '100%';
        watermarkDiv.style.zIndex = '9999';
        watermarkDiv.style.opacity = '0.1';
        watermarkDiv.style.background = 'transparent';
        watermarkDiv.style.overflow = 'hidden';
        watermarkDiv.style.display = 'flex';
        watermarkDiv.style.justifyContent = 'center';
        watermarkDiv.style.alignItems = 'center';
        watermarkDiv.style.flexWrap = 'wrap';

        var watermarkText = document.createElement('div');
        watermarkText.innerText = text;
        watermarkText.style.color = 'black';
        watermarkText.style.fontSize = '30px';
        watermarkText.style.transform = 'rotate(-30deg)';
        watermarkText.style.whiteSpace = 'nowrap';
        watermarkText.style.margin = '80px';

        for (var i = 0; i < 100; i++) {
            watermarkDiv.appendChild(watermarkText.cloneNode(true));
        }

        document.body.appendChild(watermarkDiv);
    }

    function showAlertMessage(message) {
        var alertMessage = document.createElement('div');
        alertMessage.className = 'alert-message';
        alertMessage.innerText = message;

        document.body.appendChild(alertMessage);

        // 3秒后添加fade-out类,使消息淡出
        setTimeout(function() {
            alertMessage.classList.add('fade-out');

            // 再等1秒(总共4秒)后删除元素
            setTimeout(function() {
                if (alertMessage.parentNode) {
                    alertMessage.parentNode.removeChild(alertMessage);
                }
            }, 200);
        }, 3000);

        // 5秒后跳转
        setTimeout(function() {
            window.location.replace(atob(redirectUrl));
        }, 5000);
    }

    // 检查当前域名是否在合法域名列表中
    if (!validDomains.includes(btoa(hostname))) {
        createWatermark(atob(validDomains[0])); // 使用合法域名列表中的第一个元素 
        showAlertMessage("警告:你当前浏览的页面非官方页面,可能存在有害信息!将在5秒后为你跳转至官方页面进行浏览!");
    }
})();
</script>
</body>
</html>

代码目的

这个代码的目的是,利用对方会无脑反代一切内容的机制,在所有页面内都插入检测 JS 代码,在网友访问时,检测当前域名是否为所设定自己博客的域名,如果不是所设定的博客域名则在网站背景中嵌入带域名水印并使用 confirm() 打断页面渲染,并弹出弹窗警示用户自动跳转回源站。 并且使用 JavaScript 动态插入水印 div 并不设置 id,class 等标识,防止对方通过u正则表达式匹配删除特定 div 元素。

代码升级

因为 JavaScript 仍然是以明文方式暴露在 HTML 中,有正则表达式匹配风险,所以如果对方使用正则表达式破坏水印 JavaScript,则会导致水印无法正常显示。反制方法也很简单:使用 JavaScript 混淆。

这里推荐一个 GitHub 上一个项目:https://github.com/javascript-obfuscator/javascript-obfuscator,该项目可以对 JavaScript 进行混淆,官方也提供了一个在线工具:https://obfuscator.io/#code

我们可以借此对水印部分的 JavaScript 进行混淆,防止对水印 JavaScript 部分进行正则表达式匹配破坏,上面代码经过中等级混淆后如下:

function _0x1244(_0x2e9cd0,_0x16f71d){var _0x2ccdb5=_0x2ccd();return _0x1244=function(_0x124436,_0x222862){_0x124436=_0x124436-0x1d3;var _0x36d7fe=_0x2ccdb5[_0x124436];return _0x36d7fe;},_0x1244(_0x2e9cd0,_0x16f71d);}function _0x2ccd(){var _0x519334=['4159181SScBxf','center','110%','pointerEvents','80px','left','fixed','parentNode','117310NCrasO','width','33428dRtpro','wrap','hostname','fade-out','background','flex','30px','85638ogEylA','none','black','0.1','flexWrap','location','opacity','transform','10FNisEK','whiteSpace','position','body','100%','createElement','rotate(-30deg)','port','transparent','hidden','36vpXQzg','1078040hBJRkh','overflow','4510488GmCyEv','display','div','1243HhykLg','294OWGOMk','alert-message','-5%','margin','cloneNode','justifyContent','appendChild','alignItems','fontSize','zIndex','警告:你当前浏览的页面非官方页面,可能存在有害信息!将在5秒后为你跳转至官方页面进行浏览!','add','4592382EinlGm','36cjOBwx','innerText','removeChild','5neLlLf','style','includes'];_0x2ccd=function(){return _0x519334;};return _0x2ccd();}(function(_0x4df09c,_0x8f741a){var _0x8f2856=_0x1244,_0x22b1d8=_0x4df09c();while(!![]){try{var _0x5f3be6=-parseInt(_0x8f2856(0x1f2))/0x1*(parseInt(_0x8f2856(0x201))/0x2)+-parseInt(_0x8f2856(0x1e1))/0x3+-parseInt(_0x8f2856(0x20e))/0x4*(-parseInt(_0x8f2856(0x1e5))/0x5)+-parseInt(_0x8f2856(0x1f9))/0x6*(-parseInt(_0x8f2856(0x1d5))/0x7)+-parseInt(_0x8f2856(0x20c))/0x8*(-parseInt(_0x8f2856(0x20b))/0x9)+parseInt(_0x8f2856(0x1f0))/0xa*(parseInt(_0x8f2856(0x1d4))/0xb)+parseInt(_0x8f2856(0x1e2))/0xc*(-parseInt(_0x8f2856(0x1e8))/0xd);if(_0x5f3be6===_0x8f741a)break;else _0x22b1d8['push'](_0x22b1d8['shift']());}catch(_0x3801aa){_0x22b1d8['push'](_0x22b1d8['shift']());}}}(_0x2ccd,0xe404e),(function(){var _0x2a9a37=_0x1244,_0x3507a2=['Z29ycGVsbi50b3A='],_0x49805e='aHR0cHM6Ly9nb3JwZWxuLnRvcA==',_0x2e6736=document['location'][_0x2a9a37(0x1f4)]+(document[_0x2a9a37(0x1fe)][_0x2a9a37(0x208)]?':'+document['location']['port']:'');function _0xc49f33(_0x38600e){var _0x202c5e=_0x2a9a37,_0x2660f1=document['createElement']('div');_0x2660f1['style'][_0x202c5e(0x1eb)]=_0x202c5e(0x1fa),_0x2660f1[_0x202c5e(0x1e6)][_0x202c5e(0x203)]=_0x202c5e(0x1ee),_0x2660f1['style']['top']='0',_0x2660f1[_0x202c5e(0x1e6)][_0x202c5e(0x1ed)]=_0x202c5e(0x1d7),_0x2660f1['style'][_0x202c5e(0x1f1)]=_0x202c5e(0x1ea),_0x2660f1['style']['height']=_0x202c5e(0x205),_0x2660f1[_0x202c5e(0x1e6)][_0x202c5e(0x1de)]='9999',_0x2660f1[_0x202c5e(0x1e6)][_0x202c5e(0x1ff)]=_0x202c5e(0x1fc),_0x2660f1['style'][_0x202c5e(0x1f6)]=_0x202c5e(0x209),_0x2660f1[_0x202c5e(0x1e6)][_0x202c5e(0x20d)]=_0x202c5e(0x20a),_0x2660f1[_0x202c5e(0x1e6)][_0x202c5e(0x20f)]=_0x202c5e(0x1f7),_0x2660f1['style'][_0x202c5e(0x1da)]=_0x202c5e(0x1e9),_0x2660f1[_0x202c5e(0x1e6)][_0x202c5e(0x1dc)]=_0x202c5e(0x1e9),_0x2660f1[_0x202c5e(0x1e6)][_0x202c5e(0x1fd)]=_0x202c5e(0x1f3);var _0x323b98=document[_0x202c5e(0x206)](_0x202c5e(0x1d3));_0x323b98[_0x202c5e(0x1e3)]=_0x38600e,_0x323b98[_0x202c5e(0x1e6)]['color']=_0x202c5e(0x1fb),_0x323b98[_0x202c5e(0x1e6)][_0x202c5e(0x1dd)]=_0x202c5e(0x1f8),_0x323b98[_0x202c5e(0x1e6)][_0x202c5e(0x200)]=_0x202c5e(0x207),_0x323b98['style'][_0x202c5e(0x202)]='nowrap',_0x323b98[_0x202c5e(0x1e6)][_0x202c5e(0x1d8)]=_0x202c5e(0x1ec);for(var _0x17c22c=0x0;_0x17c22c<0x64;_0x17c22c++){_0x2660f1[_0x202c5e(0x1db)](_0x323b98[_0x202c5e(0x1d9)](!![]));}document[_0x202c5e(0x204)][_0x202c5e(0x1db)](_0x2660f1);}function _0x1aa9d7(_0x4e583e){var _0x37bf9d=_0x2a9a37,_0x4d1163=document[_0x37bf9d(0x206)]('div');_0x4d1163['className']=_0x37bf9d(0x1d6),_0x4d1163[_0x37bf9d(0x1e3)]=_0x4e583e,document[_0x37bf9d(0x204)][_0x37bf9d(0x1db)](_0x4d1163),setTimeout(function(){var _0x3d022c=_0x37bf9d;_0x4d1163['classList'][_0x3d022c(0x1e0)](_0x3d022c(0x1f5)),setTimeout(function(){var _0x68fa28=_0x3d022c;_0x4d1163[_0x68fa28(0x1ef)]&&_0x4d1163[_0x68fa28(0x1ef)][_0x68fa28(0x1e4)](_0x4d1163);},0xc8);},0xbb8),setTimeout(function(){var _0x528155=_0x37bf9d;window[_0x528155(0x1fe)]['replace'](atob(_0x49805e));},0x1388);}!_0x3507a2[_0x2a9a37(0x1e7)](btoa(_0x2e6736))&&(_0xc49f33(atob(_0x3507a2[0x0])),_0x1aa9d7(_0x2a9a37(0x1df)));}()));

效果示意

20240824212126442

其他方法

1、向 google、域名注册商 、域名解析商举报

  • cloudflare 举报:https://abuse.cloudflare.com/dmca
  • google 举报:https://support.google.com/legal/answer/3110420?visit_id=638624243885343005-291301472&rd=1
  • 阿里云举报:https://report.aliyun.com/form/phishingForm

2、设置 IP 黑名单

  • 进入自己的服务器设置或者是虚拟主机管理,找到防火墙有的叫黑名单,把对方的 IP 地址添加进行,屏蔽访问和请求自己网站服务器

3、向谷歌申请移除镜像站的搜索结果

  • 因为它会原样照搬反代网页,那其实你可以通过HTML 标记验证方式在 Google Search Console 里把他的反代域名也认证到你自己名下,然后在Google Search Console 向谷歌申请移除搜索结果,嘿嘿😋

Follow - 订阅一切

2024-07-06 08:00:00

Follow是什么?

Follow 是一款面向未来的信息浏览器,致力于将各种信息源整合在一个平台上,让用户便捷地获取和管理资讯。无论是传统的 RSS 订阅、社交媒体账号、博客、播客,还是实时通知,Follow 都能帮您一站式浏览。界面简洁,操作迅速,为用户提供现代化的阅读体验。

Follow的slogan是:Next generation information browser

Follow的主要特色:

  • 信息一体化管理:Follow 支持广泛的信息源,除了传统的 RSS,还包括 Twitter、Instagram、YouTube 等社交平台,用户可以在一个界面中浏览全部订阅内容,方便直观。

  • 智能化 AI 功能:内置的 AI 不仅能实现内容翻译和摘要,还能每日生成两次个性化报告,提炼重要信息,帮助用户轻松跟踪最关心的动态。此外,Follow 还能根据您的订阅喜好建立个性化知识库。

  • 区块链激励机制:Follow 通过区块链技术为活跃用户和内容创作者提供动力代币奖励,鼓励用户积极参与和分享内容,提升整体使用体验。

  • 社交功能:Follow 也具备社交平台属性,用户可以关注他人,分享订阅列表,发现新内容。支持与好友同步订阅列表,便捷地分享和发现优质资源。

20240706111415430

Follow的访问隐忧

  • 由于大平台都可以进行订阅,这种行为在某种程度上会触动大平台的利益。
  • follow的服务器并不在国内,且爬虫本身就自带法律风险。这些都有可能影响到国内对follow应用的访问。
  • 即使现在可以使用,也并不代表未来能一直访问(直连)。

Follow认证

Follow的另一个亮点是支持打赏功能,你可以给你喜欢的文章进行打赏,当然前提是这个文章所有者进行了Follow认证,打赏的金额才能进入到他的账户中去。Follow使用的打赏货币名为power,是一种区块链货币,按照官方的说法会根据在Follow上的活跃度和贡献值来获取power。

1.获取认证码

在Follow中订阅自己博客,然后点击订阅源,申请认证(Claim),便可获取认证码。如下

This message is used to verify that this feed (feedId:73252521066438656) belongs to me (userId:75520668589921280). Join me in enjoying the next generation information browser https://follow.is.

2.验证认证码

在你自己博客中发布一篇博文,内容为刚生成的认证码,然后在Follow中再次点击申请认证(Claim),即可完成认证。认证完成后认证码的相关博文信息就可以删除了。

Follow订阅

目前gorpeln’s Blog已经过认证,在搜索框中直接输入『 gorpeln 』可直接订阅我的更新动态。或者直接填入gorpeln的RSS地址也是可以的 https://gorpeln.top/feed.xml

20240706111415431

其他top订阅可以访问github开源项目top-rss-list