mirror of
				https://github.com/bestnite/sub2sing-box.git
				synced 2025-11-04 04:40:37 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			288 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			288 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!DOCTYPE html>
 | 
						|
<html lang="zh-CN" data-bs-theme="light">
 | 
						|
  <head>
 | 
						|
    <meta charset="UTF-8" />
 | 
						|
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
						|
    <title>sub2sing-box</title>
 | 
						|
    <!-- 引入 Bootstrap CSS -->
 | 
						|
    <link
 | 
						|
      rel="stylesheet"
 | 
						|
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
 | 
						|
    />
 | 
						|
    <style>
 | 
						|
      .rename-group {
 | 
						|
        margin-bottom: 10px;
 | 
						|
      }
 | 
						|
    </style>
 | 
						|
  </head>
 | 
						|
 | 
						|
  <body>
 | 
						|
    <div class="container my-5">
 | 
						|
      <h2>
 | 
						|
        <a
 | 
						|
          href="https://github.com/nitezs/sub2sing-box"
 | 
						|
          target="_blank"
 | 
						|
          class="text-decoration-none"
 | 
						|
          >sub2sing-box</a
 | 
						|
        >
 | 
						|
      </h2>
 | 
						|
      <div id="form">
 | 
						|
        <div class="card my-4">
 | 
						|
          <div class="card-header">节点</div>
 | 
						|
          <div class="card-body">
 | 
						|
            <!-- Subscription -->
 | 
						|
            <div class="input-group mb-3">
 | 
						|
              <span class="input-group-text">订阅链接</span>
 | 
						|
              <textarea
 | 
						|
                class="form-control"
 | 
						|
                id="subscription"
 | 
						|
                name="subscription"
 | 
						|
                placeholder="一行一个"
 | 
						|
              ></textarea>
 | 
						|
            </div>
 | 
						|
 | 
						|
            <!-- Proxy -->
 | 
						|
            <div class="input-group mb-3">
 | 
						|
              <span class="input-group-text">节点分享链接</span>
 | 
						|
              <textarea
 | 
						|
                class="form-control"
 | 
						|
                id="proxy"
 | 
						|
                name="proxy"
 | 
						|
                placeholder="一行一个"
 | 
						|
              ></textarea>
 | 
						|
            </div>
 | 
						|
 | 
						|
            <!-- Delete -->
 | 
						|
            <div class="input-group mb-3">
 | 
						|
              <span class="input-group-text">删除节点:</span>
 | 
						|
              <input
 | 
						|
                type="text"
 | 
						|
                class="form-control"
 | 
						|
                id="delete"
 | 
						|
                name="delete"
 | 
						|
                placeholder="支持正则表达式"
 | 
						|
              />
 | 
						|
            </div>
 | 
						|
 | 
						|
            <!-- Rename -->
 | 
						|
            <div class="input-group mb-2">
 | 
						|
              <span class="input-group-text">重命名节点</span>
 | 
						|
              <button
 | 
						|
                type="button"
 | 
						|
                class="btn btn-primary btn-sm"
 | 
						|
                onclick="addRenameField()"
 | 
						|
              >
 | 
						|
                +
 | 
						|
              </button>
 | 
						|
            </div>
 | 
						|
 | 
						|
            <div id="renameContainer"></div>
 | 
						|
          </div>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <div class="card my-4">
 | 
						|
          <div class="card-header">模板</div>
 | 
						|
          <div class="card-body">
 | 
						|
            <!-- Template -->
 | 
						|
            <div class="form-group">
 | 
						|
              <input
 | 
						|
                type="text"
 | 
						|
                class="form-control"
 | 
						|
                id="template"
 | 
						|
                name="template"
 | 
						|
              />
 | 
						|
            </div>
 | 
						|
          </div>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <div class="card my-4">
 | 
						|
          <div class="card-header">国家策略组</div>
 | 
						|
          <div class="card-body">
 | 
						|
            <!-- Group -->
 | 
						|
            <div class="form-check">
 | 
						|
              <input
 | 
						|
                type="checkbox"
 | 
						|
                class="form-check-input"
 | 
						|
                id="group"
 | 
						|
                name="group"
 | 
						|
              />
 | 
						|
              <label for="group">启用</label>
 | 
						|
            </div>
 | 
						|
 | 
						|
            <!-- GroupType -->
 | 
						|
            <div class="input-group mb-3">
 | 
						|
              <span class="input-group-text">类型</span>
 | 
						|
              <input
 | 
						|
                type="text"
 | 
						|
                class="form-control"
 | 
						|
                id="group-type"
 | 
						|
                name="group-type"
 | 
						|
                value="selector"
 | 
						|
              />
 | 
						|
            </div>
 | 
						|
 | 
						|
            <!-- Sort -->
 | 
						|
            <div class="input-group mb-3">
 | 
						|
              <span class="input-group-text">排序依据</span>
 | 
						|
              <select class="form-select" name="sort" id="sort">
 | 
						|
                <option value="tag" selected>节点名</option>
 | 
						|
                <option value="num">节点数量</option>
 | 
						|
              </select>
 | 
						|
            </div>
 | 
						|
 | 
						|
            <!-- SortType -->
 | 
						|
            <div class="input-group">
 | 
						|
              <span class="input-group-text">排序方式</span>
 | 
						|
              <select class="form-select" name="sort-type" id="sort-type">
 | 
						|
                <option value="asc" selected>升序</option>
 | 
						|
                <option value="desc">降序</option>
 | 
						|
              </select>
 | 
						|
            </div>
 | 
						|
          </div>
 | 
						|
        </div>
 | 
						|
        <div class="card">
 | 
						|
          <div class="card-header">生成链接</div>
 | 
						|
          <div class="card-body">
 | 
						|
            <!-- Output -->
 | 
						|
            <div class="form-group">
 | 
						|
              <textarea
 | 
						|
                class="form-control"
 | 
						|
                id="output"
 | 
						|
                name="output"
 | 
						|
              ></textarea>
 | 
						|
            </div>
 | 
						|
          </div>
 | 
						|
        </div>
 | 
						|
      </div>
 | 
						|
    </div>
 | 
						|
    <link
 | 
						|
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
 | 
						|
      rel="stylesheet"
 | 
						|
      integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
 | 
						|
      crossorigin="anonymous"
 | 
						|
    />
 | 
						|
    <script
 | 
						|
      src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
 | 
						|
      integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
 | 
						|
      crossorigin="anonymous"
 | 
						|
    ></script>
 | 
						|
    <script>
 | 
						|
      init();
 | 
						|
 | 
						|
      function init() {
 | 
						|
        listenInput();
 | 
						|
      }
 | 
						|
 | 
						|
      function encodeBase64(str) {
 | 
						|
        return btoa(
 | 
						|
          encodeURIComponent(str).replace(
 | 
						|
            /%([0-9A-F]{2})/g,
 | 
						|
            function (match, p1) {
 | 
						|
              return String.fromCharCode("0x" + p1);
 | 
						|
            }
 | 
						|
          )
 | 
						|
        )
 | 
						|
          .replace(/\+/g, "-")
 | 
						|
          .replace(/\//g, "_");
 | 
						|
      }
 | 
						|
 | 
						|
      function decodeBase64(str) {
 | 
						|
        return decodeURIComponent(
 | 
						|
          Array.prototype.map
 | 
						|
            .call(atob(str), function (c) {
 | 
						|
              return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
 | 
						|
            })
 | 
						|
            .join("")
 | 
						|
        );
 | 
						|
      }
 | 
						|
 | 
						|
      function listenInput() {
 | 
						|
        const inputs = document.querySelectorAll("#form input, #form textarea");
 | 
						|
        for (let input of inputs) {
 | 
						|
          input.addEventListener("input", generateLink);
 | 
						|
        }
 | 
						|
        const selects = document.querySelectorAll("#form select");
 | 
						|
        for (let select of selects) {
 | 
						|
          select.addEventListener("change", generateLink);
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      function cleanLisnter() {
 | 
						|
        const inputs = document.querySelectorAll("#form input, #form textarea");
 | 
						|
        for (let input of inputs) {
 | 
						|
          input.removeEventListener("input", generateLink);
 | 
						|
        }
 | 
						|
        const selects = document.querySelectorAll("#form select");
 | 
						|
        for (let select of selects) {
 | 
						|
          select.removeEventListener("change", generateLink);
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      function addRenameField() {
 | 
						|
        cleanLisnter();
 | 
						|
        const container = document.getElementById("renameContainer");
 | 
						|
        const fieldHTML = `<div class="rename-group input-group">
 | 
						|
                    <input type="text" class="form-control" name="rename_from[]" placeholder="原字符(支持正则表达式)">
 | 
						|
                    <input type="text" class="form-control" name="rename_to[]" placeholder="替换字符">
 | 
						|
                    <button type="button" class="btn btn-danger" onclick="removeThisField(this)">-</button>
 | 
						|
                </div>`;
 | 
						|
        container.insertAdjacentHTML("beforeend", fieldHTML);
 | 
						|
        listenInput();
 | 
						|
      }
 | 
						|
 | 
						|
      function removeThisField(button) {
 | 
						|
        cleanLisnter();
 | 
						|
        button.parentElement.remove();
 | 
						|
        generateLink();
 | 
						|
        listenInput();
 | 
						|
      }
 | 
						|
 | 
						|
      function generateLink() {
 | 
						|
        const subscription = document
 | 
						|
          .getElementById("subscription")
 | 
						|
          .value.split("\n")
 | 
						|
          .filter((i) => i);
 | 
						|
        const proxy = document
 | 
						|
          .getElementById("proxy")
 | 
						|
          .value.split("\n")
 | 
						|
          .filter((i) => i);
 | 
						|
        const deleteRule = document.getElementById("delete").value;
 | 
						|
        const template = document.getElementById("template").value;
 | 
						|
        const renameFrom = Array.from(
 | 
						|
          document.getElementsByName("rename_from[]")
 | 
						|
        ).map((input) => input.value);
 | 
						|
        const renameTo = Array.from(
 | 
						|
          document.getElementsByName("rename_to[]")
 | 
						|
        ).map((input) => input.value);
 | 
						|
        const output = document.getElementById("output");
 | 
						|
        const group = document.getElementById("group").checked;
 | 
						|
        const groupType = document.getElementById("group-type").value;
 | 
						|
        const sort = document.getElementById("sort").value;
 | 
						|
        const sortType = document.getElementById("sort-type").value;
 | 
						|
 | 
						|
        let rename = {};
 | 
						|
        for (let i = 0; i < renameFrom.length; i++) {
 | 
						|
          if (renameFrom[i] && renameTo[i]) {
 | 
						|
            rename[renameFrom[i]] = renameTo[i];
 | 
						|
          }
 | 
						|
        }
 | 
						|
        const data = {
 | 
						|
          subscription,
 | 
						|
          proxy,
 | 
						|
          delete: deleteRule,
 | 
						|
          template,
 | 
						|
          rename,
 | 
						|
          group,
 | 
						|
          "group-type": groupType,
 | 
						|
          sort,
 | 
						|
          "sort-type": sortType,
 | 
						|
        };
 | 
						|
 | 
						|
        output.value = `${window.location.origin}/convert?data=${encodeBase64(
 | 
						|
          JSON.stringify(data)
 | 
						|
        )}`;
 | 
						|
      }
 | 
						|
    </script>
 | 
						|
  </body>
 | 
						|
</html>
 |