mirror of
https://github.com/bolucat/Archive.git
synced 2026-04-23 00:17:16 +08:00
Update On Sat Jul 6 20:29:38 CEST 2024
This commit is contained in:
@@ -694,3 +694,4 @@ Update On Tue Jul 2 20:34:08 CEST 2024
|
||||
Update On Wed Jul 3 20:29:03 CEST 2024
|
||||
Update On Thu Jul 4 20:30:48 CEST 2024
|
||||
Update On Fri Jul 5 20:32:45 CEST 2024
|
||||
Update On Sat Jul 6 20:29:28 CEST 2024
|
||||
|
||||
Generated
+2
@@ -869,6 +869,7 @@ dependencies = [
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
"clap",
|
||||
"cocoa 0.25.0",
|
||||
"ctrlc",
|
||||
"dashmap 6.0.1",
|
||||
"deelevate",
|
||||
@@ -890,6 +891,7 @@ dependencies = [
|
||||
"md-5",
|
||||
"nanoid",
|
||||
"num_cpus",
|
||||
"objc",
|
||||
"once_cell",
|
||||
"open 5.2.0",
|
||||
"parking_lot",
|
||||
|
||||
@@ -101,6 +101,10 @@ md-5 = "0.10.6"
|
||||
hex = "0.4"
|
||||
rand = "0.8"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
cocoa = "0.25.0"
|
||||
objc = "0.2.7"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
deelevate = "0.2.0"
|
||||
winreg = { version = "0.52", features = ["transactions"] }
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
windows_subsystem = "windows"
|
||||
)]
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[macro_use]
|
||||
extern crate cocoa;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[macro_use]
|
||||
extern crate objc;
|
||||
|
||||
mod cmds;
|
||||
mod config;
|
||||
mod core;
|
||||
|
||||
@@ -17,6 +17,40 @@ use serde_yaml::Mapping;
|
||||
use std::net::TcpListener;
|
||||
use tauri::{api::process::Command, App, AppHandle, Manager};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn set_window_controls_pos(window: cocoa::base::id, x: f64, y: f64) {
|
||||
use cocoa::{
|
||||
appkit::{NSView, NSWindow, NSWindowButton},
|
||||
foundation::NSRect,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let close = window.standardWindowButton_(NSWindowButton::NSWindowCloseButton);
|
||||
let miniaturize = window.standardWindowButton_(NSWindowButton::NSWindowMiniaturizeButton);
|
||||
let zoom = window.standardWindowButton_(NSWindowButton::NSWindowZoomButton);
|
||||
|
||||
let title_bar_container_view = close.superview().superview();
|
||||
|
||||
let close_rect: NSRect = msg_send![close, frame];
|
||||
let button_height = close_rect.size.height;
|
||||
|
||||
let title_bar_frame_height = button_height + y;
|
||||
let mut title_bar_rect = NSView::frame(title_bar_container_view);
|
||||
title_bar_rect.size.height = title_bar_frame_height;
|
||||
title_bar_rect.origin.y = NSView::frame(window).size.height - title_bar_frame_height;
|
||||
let _: () = msg_send![title_bar_container_view, setFrame: title_bar_rect];
|
||||
|
||||
let window_buttons = vec![close, miniaturize, zoom];
|
||||
let space_between = NSView::frame(miniaturize).origin.x - NSView::frame(close).origin.x;
|
||||
|
||||
for (i, button) in window_buttons.into_iter().enumerate() {
|
||||
let mut rect: NSRect = NSView::frame(button);
|
||||
rect.origin.x = x + (i as f64 * space_between);
|
||||
button.setFrameOrigin(rect.origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_unused_port() -> Result<u16> {
|
||||
match TcpListener::bind("127.0.0.1:0") {
|
||||
Ok(listener) => {
|
||||
@@ -244,6 +278,18 @@ pub fn create_window(app_handle: &AppHandle) {
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
fn set_controls_and_log_error(app_handle: &tauri::AppHandle, window_name: &str) {
|
||||
match app_handle.get_window(window_name).unwrap().ns_window() {
|
||||
Ok(raw_window) => {
|
||||
let window_id: cocoa::base::id = raw_window as _;
|
||||
set_window_controls_pos(window_id, 33.0, 26.0);
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!(target: "app", "failed to get ns_window, {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match builder
|
||||
.decorations(true)
|
||||
.hidden_title(true)
|
||||
@@ -252,9 +298,16 @@ pub fn create_window(app_handle: &AppHandle) {
|
||||
{
|
||||
Ok(win) => {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
win.open_devtools();
|
||||
}
|
||||
win.open_devtools();
|
||||
|
||||
set_controls_and_log_error(&app_handle, "main");
|
||||
|
||||
let app_handle_clone = app_handle.clone();
|
||||
win.on_window_event(move |event| {
|
||||
if let tauri::WindowEvent::Resized(_) = event {
|
||||
set_controls_and_log_error(&app_handle_clone, "main");
|
||||
}
|
||||
});
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!(target: "app", "failed to create window, {err}");
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"@mui/icons-material": "5.16.0",
|
||||
"@mui/lab": "5.0.0-alpha.171",
|
||||
"@mui/material": "5.16.0",
|
||||
"@mui/x-data-grid": "7.8.0",
|
||||
"@mui/x-data-grid": "7.9.0",
|
||||
"@nyanpasu/interface": "workspace:^",
|
||||
"@nyanpasu/ui": "workspace:^",
|
||||
"@tauri-apps/api": "1.6.0",
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
|
||||
import { LayoutControl } from "../layout/layout-control";
|
||||
import styles from "./app-container.module.scss";
|
||||
import AppDrawer from "./app-drawer";
|
||||
import { alpha, useTheme } from "@mui/material";
|
||||
|
||||
const OS = getSystem();
|
||||
|
||||
@@ -21,6 +22,8 @@ export const AppContainer = ({
|
||||
// wait: 100,
|
||||
// });
|
||||
|
||||
const { palette } = useTheme();
|
||||
|
||||
return (
|
||||
<Paper
|
||||
square
|
||||
@@ -46,7 +49,17 @@ export const AppContainer = ({
|
||||
<LayoutControl className="fixed right-6 top-1.5 !z-50" />
|
||||
)}
|
||||
|
||||
<div className="h-9" data-windrag />
|
||||
{OS === "macos" && (
|
||||
<div
|
||||
className="fixed z-50 left-6 top-3 h-8 w-[4.5rem] rounded-full"
|
||||
style={{ backgroundColor: alpha(palette.primary.main, 0.1) }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div
|
||||
className={OS === "macos" ? "h-[2.75rem]" : "h-9"}
|
||||
data-windrag
|
||||
/>
|
||||
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -7,6 +7,8 @@ import { useState } from "react";
|
||||
import { Panel } from "react-resizable-panels";
|
||||
import AnimatedLogo from "../layout/animated-logo";
|
||||
import RouteListItem from "./modules/route-list-item";
|
||||
import { classNames } from "@/utils";
|
||||
import getSystem from "@/utils/get-system";
|
||||
|
||||
export const AppDrawer = ({ isDrawer }: { isDrawer?: boolean }) => {
|
||||
const { palette } = useTheme();
|
||||
@@ -21,7 +23,7 @@ export const AppDrawer = ({ isDrawer }: { isDrawer?: boolean }) => {
|
||||
className={clsx(
|
||||
isDrawer ? ["max-w-60", "min-w-28"] : "w-full",
|
||||
"p-4",
|
||||
"pt-8",
|
||||
getSystem() === "macos" ? "pt-14" : "pt-8",
|
||||
"h-full",
|
||||
"flex",
|
||||
"flex-col",
|
||||
@@ -70,7 +72,10 @@ export const AppDrawer = ({ isDrawer }: { isDrawer?: boolean }) => {
|
||||
const DrawerTitle = () => {
|
||||
return (
|
||||
<div
|
||||
className="flex items-center gap-2 fixed z-10 top-1.5 left-6"
|
||||
className={classNames(
|
||||
"flex items-center gap-2 fixed z-10",
|
||||
getSystem() === "macos" ? "left-[6.5rem] top-3" : "left-6 top-1.5",
|
||||
)}
|
||||
data-windrag
|
||||
>
|
||||
<IconButton
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"latest": {
|
||||
"mihomo": "v1.18.6",
|
||||
"mihomo_alpha": "alpha-0e22876",
|
||||
"clash_rs": "v0.1.18",
|
||||
"clash_rs": "v0.1.19",
|
||||
"clash_premium": "2023-09-05-gdcc8d87"
|
||||
},
|
||||
"arch_template": {
|
||||
@@ -36,5 +36,5 @@
|
||||
"darwin-x64": "clash-darwin-amd64-n{}.gz"
|
||||
}
|
||||
},
|
||||
"updated_at": "2024-07-01T22:20:09.970Z"
|
||||
"updated_at": "2024-07-05T22:20:22.228Z"
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
"@tauri-apps/cli": "1.6.0",
|
||||
"@types/fs-extra": "11.0.4",
|
||||
"@types/lodash-es": "4.17.12",
|
||||
"@types/node": "20.14.9",
|
||||
"@types/node": "20.14.10",
|
||||
"autoprefixer": "10.4.19",
|
||||
"conventional-changelog-conventionalcommits": "8.0.0",
|
||||
"cross-env": "7.0.3",
|
||||
|
||||
Generated
+65
-121
@@ -24,7 +24,7 @@ importers:
|
||||
devDependencies:
|
||||
'@commitlint/cli':
|
||||
specifier: 19.3.0
|
||||
version: 19.3.0(@types/node@20.14.9)(typescript@5.5.3)
|
||||
version: 19.3.0(@types/node@20.14.10)(typescript@5.5.3)
|
||||
'@commitlint/config-conventional':
|
||||
specifier: 19.2.2
|
||||
version: 19.2.2
|
||||
@@ -38,8 +38,8 @@ importers:
|
||||
specifier: 4.17.12
|
||||
version: 4.17.12
|
||||
'@types/node':
|
||||
specifier: 20.14.9
|
||||
version: 20.14.9
|
||||
specifier: 20.14.10
|
||||
version: 20.14.10
|
||||
autoprefixer:
|
||||
specifier: 10.4.19
|
||||
version: 10.4.19(postcss@8.4.39)
|
||||
@@ -178,7 +178,7 @@ importers:
|
||||
version: 11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
'@generouted/react-router':
|
||||
specifier: 1.19.5
|
||||
version: 1.19.5(react-router-dom@6.24.1(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(vite@5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))
|
||||
version: 1.19.5(react-router-dom@6.24.1(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))
|
||||
'@juggle/resize-observer':
|
||||
specifier: 3.4.0
|
||||
version: 3.4.0
|
||||
@@ -195,8 +195,8 @@ importers:
|
||||
specifier: 5.16.0
|
||||
version: 5.16.0(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
'@mui/x-data-grid':
|
||||
specifier: 7.8.0
|
||||
version: 7.8.0(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@mui/material@5.16.0(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
specifier: 7.9.0
|
||||
version: 7.9.0(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@mui/material@5.16.0(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
'@nyanpasu/interface':
|
||||
specifier: workspace:^
|
||||
version: link:../interface
|
||||
@@ -299,10 +299,10 @@ importers:
|
||||
version: 7.15.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@vitejs/plugin-react':
|
||||
specifier: 4.3.1
|
||||
version: 4.3.1(vite@5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))
|
||||
version: 4.3.1(vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))
|
||||
'@vitejs/plugin-react-swc':
|
||||
specifier: 3.7.0
|
||||
version: 3.7.0(vite@5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))
|
||||
version: 3.7.0(vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))
|
||||
clsx:
|
||||
specifier: 2.1.1
|
||||
version: 2.1.1
|
||||
@@ -320,19 +320,19 @@ importers:
|
||||
version: 2.1.3
|
||||
vite:
|
||||
specifier: 5.3.3
|
||||
version: 5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
version: 5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
vite-plugin-monaco-editor:
|
||||
specifier: npm:vite-plugin-monaco-editor-new@1.1.3
|
||||
version: vite-plugin-monaco-editor-new@1.1.3(monaco-editor@0.50.0)
|
||||
vite-plugin-sass-dts:
|
||||
specifier: 1.3.22
|
||||
version: 1.3.22(postcss@8.4.39)(prettier@3.3.2)(sass@1.77.6)(vite@5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))
|
||||
version: 1.3.22(postcss@8.4.39)(prettier@3.3.2)(sass@1.77.6)(vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))
|
||||
vite-plugin-svgr:
|
||||
specifier: 4.2.0
|
||||
version: 4.2.0(rollup@4.17.2)(typescript@5.5.3)(vite@5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))
|
||||
version: 4.2.0(rollup@4.17.2)(typescript@5.5.3)(vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))
|
||||
vite-tsconfig-paths:
|
||||
specifier: 4.3.2
|
||||
version: 4.3.2(typescript@5.5.3)(vite@5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))
|
||||
version: 4.3.2(typescript@5.5.3)(vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))
|
||||
|
||||
frontend/ui:
|
||||
dependencies:
|
||||
@@ -1169,16 +1169,6 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/private-theming@5.15.20':
|
||||
resolution: {integrity: sha512-BK8F94AIqSrnaPYXf2KAOjGZJgWfvqAVQ2gVR3EryvQFtuBnG6RwodxrCvd3B48VuMy6Wsk897+lQMUxJyk+6g==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
peerDependencies:
|
||||
'@types/react': npm:types-react@rc
|
||||
react: npm:react@rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/private-theming@5.16.0':
|
||||
resolution: {integrity: sha512-sYpubkO1MZOnxNyVOClrPNOTs0MfuRVVnAvCeMaOaXt6GimgQbnUcshYv2pSr6PFj+Mqzdff/FYOBceK8u5QgA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
@@ -1202,22 +1192,6 @@ packages:
|
||||
'@emotion/styled':
|
||||
optional: true
|
||||
|
||||
'@mui/system@5.15.20':
|
||||
resolution: {integrity: sha512-LoMq4IlAAhxzL2VNUDBTQxAb4chnBe8JvRINVNDiMtHE2PiPOoHlhOPutSxEbaL5mkECPVWSv6p8JEV+uykwIA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
peerDependencies:
|
||||
'@emotion/react': ^11.5.0
|
||||
'@emotion/styled': ^11.3.0
|
||||
'@types/react': npm:types-react@rc
|
||||
react: npm:react@rc
|
||||
peerDependenciesMeta:
|
||||
'@emotion/react':
|
||||
optional: true
|
||||
'@emotion/styled':
|
||||
optional: true
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/system@5.16.0':
|
||||
resolution: {integrity: sha512-9YbkC2m3+pNumAvubYv+ijLtog6puJ0fJ6rYfzfLCM47pWrw3m+30nXNM8zMgDaKL6vpfWJcCXm+LPaWBpy7sw==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
@@ -1242,16 +1216,6 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/utils@5.15.20':
|
||||
resolution: {integrity: sha512-mAbYx0sovrnpAu1zHc3MDIhPqL8RPVC5W5xcO1b7PiSCJPtckIZmBkp8hefamAvUiAV8gpfMOM6Zb+eSisbI2A==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
peerDependencies:
|
||||
'@types/react': npm:types-react@rc
|
||||
react: npm:react@rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/utils@5.16.0':
|
||||
resolution: {integrity: sha512-kLLi5J1xY+mwtUlMb8Ubdxf4qFAA1+U7WPBvjM/qQ4CIwLCohNb0sHo1oYPufjSIH/Z9+dhVxD7dJlfGjd1AVA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
@@ -1262,14 +1226,20 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/x-data-grid@7.8.0':
|
||||
resolution: {integrity: sha512-X3t6EVSZ28vVKY9NfqKcClchw2o/KmHsywybp1tNFevIJiwjZSp7NDJ091GyTqMgyDt1Dy5z2hGxoTDUYYfeGg==}
|
||||
'@mui/x-data-grid@7.9.0':
|
||||
resolution: {integrity: sha512-RkrVD+tfcR/h3j2p2uqohxA00C5tCJIV5gb5+2ap8XdM0Y8XMF81bB8UADWenU5W83UTErWvtU7n4gCl7hJO9g==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@mui/material': ^5.15.14
|
||||
react: npm:react@rc
|
||||
react-dom: npm:react-dom@rc
|
||||
|
||||
'@mui/x-internals@7.9.0':
|
||||
resolution: {integrity: sha512-RJRrM6moaDZ8S11gDt8OKVclKm2v9khpIyLkpenNze+tT4dQYoU3liW5P2t31hA4Na/T6JQKNosB4qmB2TYfZw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
react: npm:react@rc
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -1935,8 +1905,8 @@ packages:
|
||||
'@types/node@20.12.10':
|
||||
resolution: {integrity: sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw==}
|
||||
|
||||
'@types/node@20.14.9':
|
||||
resolution: {integrity: sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==}
|
||||
'@types/node@20.14.10':
|
||||
resolution: {integrity: sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==}
|
||||
|
||||
'@types/parse-json@4.0.2':
|
||||
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
|
||||
@@ -5905,11 +5875,11 @@ snapshots:
|
||||
'@babel/helper-validator-identifier': 7.24.5
|
||||
to-fast-properties: 2.0.0
|
||||
|
||||
'@commitlint/cli@19.3.0(@types/node@20.14.9)(typescript@5.5.3)':
|
||||
'@commitlint/cli@19.3.0(@types/node@20.14.10)(typescript@5.5.3)':
|
||||
dependencies:
|
||||
'@commitlint/format': 19.3.0
|
||||
'@commitlint/lint': 19.2.2
|
||||
'@commitlint/load': 19.2.0(@types/node@20.14.9)(typescript@5.5.3)
|
||||
'@commitlint/load': 19.2.0(@types/node@20.14.10)(typescript@5.5.3)
|
||||
'@commitlint/read': 19.2.1
|
||||
'@commitlint/types': 19.0.3
|
||||
execa: 8.0.1
|
||||
@@ -5956,7 +5926,7 @@ snapshots:
|
||||
'@commitlint/rules': 19.0.3
|
||||
'@commitlint/types': 19.0.3
|
||||
|
||||
'@commitlint/load@19.2.0(@types/node@20.14.9)(typescript@5.5.3)':
|
||||
'@commitlint/load@19.2.0(@types/node@20.14.10)(typescript@5.5.3)':
|
||||
dependencies:
|
||||
'@commitlint/config-validator': 19.0.3
|
||||
'@commitlint/execute-rule': 19.0.0
|
||||
@@ -5964,7 +5934,7 @@ snapshots:
|
||||
'@commitlint/types': 19.0.3
|
||||
chalk: 5.3.0
|
||||
cosmiconfig: 9.0.0(typescript@5.5.3)
|
||||
cosmiconfig-typescript-loader: 5.0.0(@types/node@20.14.9)(cosmiconfig@9.0.0(typescript@5.5.3))(typescript@5.5.3)
|
||||
cosmiconfig-typescript-loader: 5.0.0(@types/node@20.14.10)(cosmiconfig@9.0.0(typescript@5.5.3))(typescript@5.5.3)
|
||||
lodash.isplainobject: 4.0.6
|
||||
lodash.merge: 4.6.2
|
||||
lodash.uniq: 4.5.0
|
||||
@@ -6338,13 +6308,13 @@ snapshots:
|
||||
postcss: 7.0.32
|
||||
purgecss: 2.3.0
|
||||
|
||||
'@generouted/react-router@1.19.5(react-router-dom@6.24.1(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(vite@5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))':
|
||||
'@generouted/react-router@1.19.5(react-router-dom@6.24.1(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))':
|
||||
dependencies:
|
||||
fast-glob: 3.3.2
|
||||
generouted: 1.19.5(vite@5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))
|
||||
generouted: 1.19.5(vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))
|
||||
react: 19.0.0-rc-fb9a90fa48-20240614
|
||||
react-router-dom: 6.24.1(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)
|
||||
vite: 5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
vite: 5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
|
||||
'@humanwhocodes/config-array@0.11.14':
|
||||
dependencies:
|
||||
@@ -6450,15 +6420,6 @@ snapshots:
|
||||
'@emotion/styled': 11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
'@types/react': types-react@19.0.0-rc.1
|
||||
|
||||
'@mui/private-theming@5.15.20(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.7
|
||||
'@mui/utils': 5.15.20(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
prop-types: 15.8.1
|
||||
react: 19.0.0-rc-fb9a90fa48-20240614
|
||||
optionalDependencies:
|
||||
'@types/react': types-react@19.0.0-rc.1
|
||||
|
||||
'@mui/private-theming@5.16.0(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.7
|
||||
@@ -6479,22 +6440,6 @@ snapshots:
|
||||
'@emotion/react': 11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
'@emotion/styled': 11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
|
||||
'@mui/system@5.15.20(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.7
|
||||
'@mui/private-theming': 5.15.20(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
'@mui/styled-engine': 5.15.14(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)
|
||||
'@mui/types': 7.2.14(types-react@19.0.0-rc.1)
|
||||
'@mui/utils': 5.15.20(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
clsx: 2.1.1
|
||||
csstype: 3.1.3
|
||||
prop-types: 15.8.1
|
||||
react: 19.0.0-rc-fb9a90fa48-20240614
|
||||
optionalDependencies:
|
||||
'@emotion/react': 11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
'@emotion/styled': 11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
'@types/react': types-react@19.0.0-rc.1
|
||||
|
||||
'@mui/system@5.16.0(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.7
|
||||
@@ -6515,16 +6460,6 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': types-react@19.0.0-rc.1
|
||||
|
||||
'@mui/utils@5.15.20(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.7
|
||||
'@types/prop-types': 15.7.12
|
||||
prop-types: 15.8.1
|
||||
react: 19.0.0-rc-fb9a90fa48-20240614
|
||||
react-is: 18.3.1
|
||||
optionalDependencies:
|
||||
'@types/react': types-react@19.0.0-rc.1
|
||||
|
||||
'@mui/utils@5.16.0(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.7
|
||||
@@ -6535,12 +6470,13 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': types-react@19.0.0-rc.1
|
||||
|
||||
'@mui/x-data-grid@7.8.0(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@mui/material@5.16.0(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)':
|
||||
'@mui/x-data-grid@7.9.0(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@mui/material@5.16.0(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.7
|
||||
'@mui/material': 5.16.0(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-fb9a90fa48-20240614(react@19.0.0-rc-fb9a90fa48-20240614))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
'@mui/system': 5.15.20(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
'@mui/utils': 5.15.20(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
'@mui/system': 5.16.0(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1))(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
'@mui/utils': 5.16.0(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
'@mui/x-internals': 7.9.0(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
clsx: 2.1.1
|
||||
prop-types: 15.8.1
|
||||
react: 19.0.0-rc-fb9a90fa48-20240614
|
||||
@@ -6551,6 +6487,14 @@ snapshots:
|
||||
- '@emotion/styled'
|
||||
- '@types/react'
|
||||
|
||||
'@mui/x-internals@7.9.0(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.7
|
||||
'@mui/utils': 5.16.0(react@19.0.0-rc-fb9a90fa48-20240614)(types-react@19.0.0-rc.1)
|
||||
react: 19.0.0-rc-fb9a90fa48-20240614
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
dependencies:
|
||||
'@nodelib/fs.stat': 2.0.5
|
||||
@@ -7039,12 +6983,12 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/http-cache-semantics': 4.0.4
|
||||
'@types/keyv': 3.1.4
|
||||
'@types/node': 20.14.9
|
||||
'@types/node': 20.14.10
|
||||
'@types/responselike': 1.0.3
|
||||
|
||||
'@types/conventional-commits-parser@5.0.0':
|
||||
dependencies:
|
||||
'@types/node': 20.14.9
|
||||
'@types/node': 20.14.10
|
||||
|
||||
'@types/d3-array@3.2.1': {}
|
||||
|
||||
@@ -7178,7 +7122,7 @@ snapshots:
|
||||
'@types/fs-extra@11.0.4':
|
||||
dependencies:
|
||||
'@types/jsonfile': 6.1.4
|
||||
'@types/node': 20.14.9
|
||||
'@types/node': 20.14.10
|
||||
|
||||
'@types/geojson@7946.0.14': {}
|
||||
|
||||
@@ -7194,11 +7138,11 @@ snapshots:
|
||||
|
||||
'@types/jsonfile@6.1.4':
|
||||
dependencies:
|
||||
'@types/node': 20.14.9
|
||||
'@types/node': 20.14.10
|
||||
|
||||
'@types/keyv@3.1.4':
|
||||
dependencies:
|
||||
'@types/node': 20.14.9
|
||||
'@types/node': 20.14.10
|
||||
|
||||
'@types/lodash-es@4.17.12':
|
||||
dependencies:
|
||||
@@ -7218,7 +7162,7 @@ snapshots:
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
|
||||
'@types/node@20.14.9':
|
||||
'@types/node@20.14.10':
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
|
||||
@@ -7240,7 +7184,7 @@ snapshots:
|
||||
|
||||
'@types/responselike@1.0.3':
|
||||
dependencies:
|
||||
'@types/node': 20.14.9
|
||||
'@types/node': 20.14.10
|
||||
|
||||
'@types/unist@2.0.10': {}
|
||||
|
||||
@@ -7248,7 +7192,7 @@ snapshots:
|
||||
|
||||
'@types/yauzl@2.10.3':
|
||||
dependencies:
|
||||
'@types/node': 20.14.9
|
||||
'@types/node': 20.14.10
|
||||
optional: true
|
||||
|
||||
'@typescript-eslint/eslint-plugin@7.15.0(@typescript-eslint/parser@7.15.0(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3)':
|
||||
@@ -7334,21 +7278,21 @@ snapshots:
|
||||
|
||||
'@ungap/structured-clone@1.2.0': {}
|
||||
|
||||
'@vitejs/plugin-react-swc@3.7.0(vite@5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))':
|
||||
'@vitejs/plugin-react-swc@3.7.0(vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))':
|
||||
dependencies:
|
||||
'@swc/core': 1.6.1
|
||||
vite: 5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
vite: 5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- '@swc/helpers'
|
||||
|
||||
'@vitejs/plugin-react@4.3.1(vite@5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))':
|
||||
'@vitejs/plugin-react@4.3.1(vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0))':
|
||||
dependencies:
|
||||
'@babel/core': 7.24.5
|
||||
'@babel/plugin-transform-react-jsx-self': 7.24.5(@babel/core@7.24.5)
|
||||
'@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.24.5)
|
||||
'@types/babel__core': 7.20.5
|
||||
react-refresh: 0.14.2
|
||||
vite: 5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
vite: 5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -7836,9 +7780,9 @@ snapshots:
|
||||
dependencies:
|
||||
is-what: 3.14.1
|
||||
|
||||
cosmiconfig-typescript-loader@5.0.0(@types/node@20.14.9)(cosmiconfig@9.0.0(typescript@5.5.3))(typescript@5.5.3):
|
||||
cosmiconfig-typescript-loader@5.0.0(@types/node@20.14.10)(cosmiconfig@9.0.0(typescript@5.5.3))(typescript@5.5.3):
|
||||
dependencies:
|
||||
'@types/node': 20.14.9
|
||||
'@types/node': 20.14.10
|
||||
cosmiconfig: 9.0.0(typescript@5.5.3)
|
||||
jiti: 1.21.0
|
||||
typescript: 5.5.3
|
||||
@@ -8829,9 +8773,9 @@ snapshots:
|
||||
|
||||
functions-have-names@1.2.3: {}
|
||||
|
||||
generouted@1.19.5(vite@5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)):
|
||||
generouted@1.19.5(vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
vite: 5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
vite: 5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
|
||||
gensync@1.0.0-beta.2: {}
|
||||
|
||||
@@ -11345,43 +11289,43 @@ snapshots:
|
||||
esbuild: 0.19.12
|
||||
monaco-editor: 0.50.0
|
||||
|
||||
vite-plugin-sass-dts@1.3.22(postcss@8.4.39)(prettier@3.3.2)(sass@1.77.6)(vite@5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)):
|
||||
vite-plugin-sass-dts@1.3.22(postcss@8.4.39)(prettier@3.3.2)(sass@1.77.6)(vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
postcss: 8.4.39
|
||||
postcss-js: 4.0.1(postcss@8.4.39)
|
||||
prettier: 3.3.2
|
||||
sass: 1.77.6
|
||||
vite: 5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
vite: 5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
|
||||
vite-plugin-svgr@4.2.0(rollup@4.17.2)(typescript@5.5.3)(vite@5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)):
|
||||
vite-plugin-svgr@4.2.0(rollup@4.17.2)(typescript@5.5.3)(vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.1.0(rollup@4.17.2)
|
||||
'@svgr/core': 8.1.0(typescript@5.5.3)
|
||||
'@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.5.3))
|
||||
vite: 5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
vite: 5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite-tsconfig-paths@4.3.2(typescript@5.5.3)(vite@5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)):
|
||||
vite-tsconfig-paths@4.3.2(typescript@5.5.3)(vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
globrex: 0.1.2
|
||||
tsconfck: 3.0.3(typescript@5.5.3)
|
||||
optionalDependencies:
|
||||
vite: 5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
vite: 5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite@5.3.3(@types/node@20.14.9)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0):
|
||||
vite@5.3.3(@types/node@20.14.10)(less@4.2.0)(sass@1.77.6)(stylus@0.62.0):
|
||||
dependencies:
|
||||
esbuild: 0.21.5
|
||||
postcss: 8.4.39
|
||||
rollup: 4.17.2
|
||||
optionalDependencies:
|
||||
'@types/node': 20.14.9
|
||||
'@types/node': 20.14.10
|
||||
fsevents: 2.3.3
|
||||
less: 4.2.0
|
||||
sass: 1.77.6
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
## v1.7.3
|
||||
|
||||
### Features
|
||||
|
||||
- 支持可视化编辑订阅代理组
|
||||
- 支持可视化编辑订阅节点
|
||||
- 支持可视化编辑订阅规则
|
||||
- 扩展脚本支持订阅名称参数 `function main(config, profileName)`
|
||||
|
||||
### Bugs Fixes
|
||||
|
||||
- 代理绕过格式检查错误
|
||||
|
||||
---
|
||||
|
||||
## v1.7.2
|
||||
|
||||
### Break Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "clash-verge",
|
||||
"version": "1.7.2",
|
||||
"version": "1.7.3",
|
||||
"license": "GPL-3.0-only",
|
||||
"scripts": {
|
||||
"dev": "tauri dev",
|
||||
@@ -24,10 +24,10 @@
|
||||
"@emotion/react": "^11.11.4",
|
||||
"@emotion/styled": "^11.11.5",
|
||||
"@juggle/resize-observer": "^3.4.0",
|
||||
"@mui/icons-material": "^5.15.21",
|
||||
"@mui/icons-material": "^5.16.0",
|
||||
"@mui/lab": "5.0.0-alpha.149",
|
||||
"@mui/material": "^5.15.21",
|
||||
"@mui/x-data-grid": "^7.8.0",
|
||||
"@mui/material": "^5.16.0",
|
||||
"@mui/x-data-grid": "^7.9.0",
|
||||
"@tauri-apps/api": "^1.6.0",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"ahooks": "^3.8.0",
|
||||
|
||||
Generated
+87
-69
@@ -26,17 +26,17 @@ importers:
|
||||
specifier: ^3.4.0
|
||||
version: 3.4.0
|
||||
"@mui/icons-material":
|
||||
specifier: ^5.15.21
|
||||
version: 5.15.21(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
specifier: ^5.16.0
|
||||
version: 5.16.0(@mui/material@5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/lab":
|
||||
specifier: 5.0.0-alpha.149
|
||||
version: 5.0.0-alpha.149(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
version: 5.0.0-alpha.149(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@mui/material":
|
||||
specifier: ^5.15.21
|
||||
version: 5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
specifier: ^5.16.0
|
||||
version: 5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@mui/x-data-grid":
|
||||
specifier: ^7.8.0
|
||||
version: 7.8.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
specifier: ^7.9.0
|
||||
version: 7.9.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@tauri-apps/api":
|
||||
specifier: ^1.6.0
|
||||
version: 1.6.0
|
||||
@@ -154,10 +154,10 @@ importers:
|
||||
version: 4.4.10
|
||||
"@vitejs/plugin-legacy":
|
||||
specifier: ^5.4.1
|
||||
version: 5.4.1(terser@5.31.1)(vite@5.3.3(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.1))
|
||||
version: 5.4.1(terser@5.31.1)(vite@5.3.3(@types/node@20.14.10)(sass@1.77.6)(terser@5.31.1))
|
||||
"@vitejs/plugin-react":
|
||||
specifier: ^4.3.1
|
||||
version: 4.3.1(vite@5.3.3(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.1))
|
||||
version: 4.3.1(vite@5.3.3(@types/node@20.14.10)(sass@1.77.6)(terser@5.31.1))
|
||||
adm-zip:
|
||||
specifier: ^0.5.14
|
||||
version: 0.5.14
|
||||
@@ -193,13 +193,13 @@ importers:
|
||||
version: 5.5.3
|
||||
vite:
|
||||
specifier: ^5.3.3
|
||||
version: 5.3.3(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.1)
|
||||
version: 5.3.3(@types/node@20.14.10)(sass@1.77.6)(terser@5.31.1)
|
||||
vite-plugin-monaco-editor:
|
||||
specifier: ^1.1.0
|
||||
version: 1.1.0(monaco-editor@0.49.0)
|
||||
vite-plugin-svgr:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0(rollup@4.18.0)(typescript@5.5.3)(vite@5.3.3(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.1))
|
||||
version: 4.2.0(rollup@4.18.0)(typescript@5.5.3)(vite@5.3.3(@types/node@20.14.10)(sass@1.77.6)(terser@5.31.1))
|
||||
|
||||
packages:
|
||||
"@actions/github@5.1.1":
|
||||
@@ -1580,16 +1580,16 @@ packages:
|
||||
"@types/react":
|
||||
optional: true
|
||||
|
||||
"@mui/core-downloads-tracker@5.15.21":
|
||||
"@mui/core-downloads-tracker@5.16.0":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-dp9lXBaJZzJYeJfQY3Ow4Rb49QaCEdkl2KKYscdQHQm6bMJ+l4XPY3Cd9PCeeJTsHPIDJ60lzXbeRgs6sx/rpw==,
|
||||
integrity: sha512-8SLffXYPRVpcZx5QzxNE8fytTqzp+IuU3deZbQWg/vSaTlDpR5YVrQ4qQtXTi5cRdhOufV5INylmwlKK+//nPw==,
|
||||
}
|
||||
|
||||
"@mui/icons-material@5.15.21":
|
||||
"@mui/icons-material@5.16.0":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-yqkq1MbdkmX5ZHyvZTBuAaA6RkvoqkoAgwBSx9Oh0L0jAfj9T/Ih/NhMNjkl8PWVSonjfDUkKroBnjRyo/1M9Q==,
|
||||
integrity: sha512-6ISoOhkp9w5gD0PEW9JklrcbyARDkFWNTBdwXZ1Oy5IGlyu9B0zG0hnUIe4H17IaF1Vgj6C8VI+v4tkSdK0veg==,
|
||||
}
|
||||
engines: { node: ">=12.0.0" }
|
||||
peerDependencies:
|
||||
@@ -1621,10 +1621,10 @@ packages:
|
||||
"@types/react":
|
||||
optional: true
|
||||
|
||||
"@mui/material@5.15.21":
|
||||
"@mui/material@5.16.0":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-nTyCcgduKwHqiuQ/B03EQUa+utSMzn2sQp0QAibsnYe4tvc3zkMbO0amKpl48vhABIY3IvT6w9615BFIgMt0YA==,
|
||||
integrity: sha512-DbR1NckTLpjt9Zut9EGQ70th86HfN0BYQgyYro6aXQrNfjzSwe3BJS1AyBQ5mJ7TdL6YVRqohfukxj9JlqZZUg==,
|
||||
}
|
||||
engines: { node: ">=12.0.0" }
|
||||
peerDependencies:
|
||||
@@ -1641,10 +1641,10 @@ packages:
|
||||
"@types/react":
|
||||
optional: true
|
||||
|
||||
"@mui/private-theming@5.15.20":
|
||||
"@mui/private-theming@5.16.0":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-BK8F94AIqSrnaPYXf2KAOjGZJgWfvqAVQ2gVR3EryvQFtuBnG6RwodxrCvd3B48VuMy6Wsk897+lQMUxJyk+6g==,
|
||||
integrity: sha512-sYpubkO1MZOnxNyVOClrPNOTs0MfuRVVnAvCeMaOaXt6GimgQbnUcshYv2pSr6PFj+Mqzdff/FYOBceK8u5QgA==,
|
||||
}
|
||||
engines: { node: ">=12.0.0" }
|
||||
peerDependencies:
|
||||
@@ -1670,10 +1670,10 @@ packages:
|
||||
"@emotion/styled":
|
||||
optional: true
|
||||
|
||||
"@mui/system@5.15.20":
|
||||
"@mui/system@5.16.0":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-LoMq4IlAAhxzL2VNUDBTQxAb4chnBe8JvRINVNDiMtHE2PiPOoHlhOPutSxEbaL5mkECPVWSv6p8JEV+uykwIA==,
|
||||
integrity: sha512-9YbkC2m3+pNumAvubYv+ijLtog6puJ0fJ6rYfzfLCM47pWrw3m+30nXNM8zMgDaKL6vpfWJcCXm+LPaWBpy7sw==,
|
||||
}
|
||||
engines: { node: ">=12.0.0" }
|
||||
peerDependencies:
|
||||
@@ -1700,10 +1700,10 @@ packages:
|
||||
"@types/react":
|
||||
optional: true
|
||||
|
||||
"@mui/utils@5.15.20":
|
||||
"@mui/utils@5.16.0":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-mAbYx0sovrnpAu1zHc3MDIhPqL8RPVC5W5xcO1b7PiSCJPtckIZmBkp8hefamAvUiAV8gpfMOM6Zb+eSisbI2A==,
|
||||
integrity: sha512-kLLi5J1xY+mwtUlMb8Ubdxf4qFAA1+U7WPBvjM/qQ4CIwLCohNb0sHo1oYPufjSIH/Z9+dhVxD7dJlfGjd1AVA==,
|
||||
}
|
||||
engines: { node: ">=12.0.0" }
|
||||
peerDependencies:
|
||||
@@ -1713,10 +1713,10 @@ packages:
|
||||
"@types/react":
|
||||
optional: true
|
||||
|
||||
"@mui/x-data-grid@7.8.0":
|
||||
"@mui/x-data-grid@7.9.0":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-X3t6EVSZ28vVKY9NfqKcClchw2o/KmHsywybp1tNFevIJiwjZSp7NDJ091GyTqMgyDt1Dy5z2hGxoTDUYYfeGg==,
|
||||
integrity: sha512-RkrVD+tfcR/h3j2p2uqohxA00C5tCJIV5gb5+2ap8XdM0Y8XMF81bB8UADWenU5W83UTErWvtU7n4gCl7hJO9g==,
|
||||
}
|
||||
engines: { node: ">=14.0.0" }
|
||||
peerDependencies:
|
||||
@@ -1724,6 +1724,15 @@ packages:
|
||||
react: ^17.0.0 || ^18.0.0
|
||||
react-dom: ^17.0.0 || ^18.0.0
|
||||
|
||||
"@mui/x-internals@7.9.0":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-RJRrM6moaDZ8S11gDt8OKVclKm2v9khpIyLkpenNze+tT4dQYoU3liW5P2t31hA4Na/T6JQKNosB4qmB2TYfZw==,
|
||||
}
|
||||
engines: { node: ">=14.0.0" }
|
||||
peerDependencies:
|
||||
react: ^17.0.0 || ^18.0.0
|
||||
|
||||
"@mui/x-tree-view@6.0.0-alpha.1":
|
||||
resolution:
|
||||
{
|
||||
@@ -2268,10 +2277,10 @@ packages:
|
||||
integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==,
|
||||
}
|
||||
|
||||
"@types/node@20.14.9":
|
||||
"@types/node@20.14.10":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==,
|
||||
integrity: sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==,
|
||||
}
|
||||
|
||||
"@types/parse-json@4.0.2":
|
||||
@@ -2740,10 +2749,10 @@ packages:
|
||||
integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==,
|
||||
}
|
||||
|
||||
electron-to-chromium@1.4.816:
|
||||
electron-to-chromium@1.4.818:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-EKH5X5oqC6hLmiS7/vYtZHZFTNdhsYG5NVPRN6Yn0kQHNBlT59+xSM8HBy66P5fxWpKgZbPqb+diC64ng295Jw==,
|
||||
integrity: sha512-eGvIk2V0dGImV9gWLq8fDfTTsCAeMDwZqEPMr+jMInxZdnp9Us8UpovYpRCf9NQ7VOFgrN2doNSgvISbsbNpxA==,
|
||||
}
|
||||
|
||||
end-of-stream@1.4.4:
|
||||
@@ -5587,7 +5596,7 @@ snapshots:
|
||||
"@babel/runtime": 7.24.7
|
||||
"@floating-ui/react-dom": 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@mui/types": 7.2.14(@types/react@18.3.3)
|
||||
"@mui/utils": 5.15.20(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/utils": 5.16.0(@types/react@18.3.3)(react@18.3.1)
|
||||
"@popperjs/core": 2.11.8
|
||||
clsx: 2.1.1
|
||||
prop-types: 15.8.1
|
||||
@@ -5601,7 +5610,7 @@ snapshots:
|
||||
"@babel/runtime": 7.24.7
|
||||
"@floating-ui/react-dom": 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@mui/types": 7.2.14(@types/react@18.3.3)
|
||||
"@mui/utils": 5.15.20(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/utils": 5.16.0(@types/react@18.3.3)(react@18.3.1)
|
||||
"@popperjs/core": 2.11.8
|
||||
clsx: 2.1.1
|
||||
prop-types: 15.8.1
|
||||
@@ -5610,25 +5619,25 @@ snapshots:
|
||||
optionalDependencies:
|
||||
"@types/react": 18.3.3
|
||||
|
||||
"@mui/core-downloads-tracker@5.15.21": {}
|
||||
"@mui/core-downloads-tracker@5.16.0": {}
|
||||
|
||||
"@mui/icons-material@5.15.21(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)":
|
||||
"@mui/icons-material@5.16.0(@mui/material@5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)":
|
||||
dependencies:
|
||||
"@babel/runtime": 7.24.7
|
||||
"@mui/material": 5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@mui/material": 5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
"@types/react": 18.3.3
|
||||
|
||||
"@mui/lab@5.0.0-alpha.149(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)":
|
||||
"@mui/lab@5.0.0-alpha.149(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)":
|
||||
dependencies:
|
||||
"@babel/runtime": 7.24.7
|
||||
"@mui/base": 5.0.0-beta.20(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@mui/material": 5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@mui/system": 5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/material": 5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@mui/system": 5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/types": 7.2.14(@types/react@18.3.3)
|
||||
"@mui/utils": 5.15.20(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/x-tree-view": 6.0.0-alpha.1(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/base@5.0.0-beta.20(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@mui/utils": 5.16.0(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/x-tree-view": 6.0.0-alpha.1(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/base@5.0.0-beta.20(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/material@5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
clsx: 2.1.1
|
||||
prop-types: 15.8.1
|
||||
react: 18.3.1
|
||||
@@ -5638,14 +5647,14 @@ snapshots:
|
||||
"@emotion/styled": 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
"@types/react": 18.3.3
|
||||
|
||||
"@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)":
|
||||
"@mui/material@5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)":
|
||||
dependencies:
|
||||
"@babel/runtime": 7.24.7
|
||||
"@mui/base": 5.0.0-beta.40(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@mui/core-downloads-tracker": 5.15.21
|
||||
"@mui/system": 5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/core-downloads-tracker": 5.16.0
|
||||
"@mui/system": 5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/types": 7.2.14(@types/react@18.3.3)
|
||||
"@mui/utils": 5.15.20(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/utils": 5.16.0(@types/react@18.3.3)(react@18.3.1)
|
||||
"@types/react-transition-group": 4.4.10
|
||||
clsx: 2.1.1
|
||||
csstype: 3.1.3
|
||||
@@ -5659,10 +5668,10 @@ snapshots:
|
||||
"@emotion/styled": 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
"@types/react": 18.3.3
|
||||
|
||||
"@mui/private-theming@5.15.20(@types/react@18.3.3)(react@18.3.1)":
|
||||
"@mui/private-theming@5.16.0(@types/react@18.3.3)(react@18.3.1)":
|
||||
dependencies:
|
||||
"@babel/runtime": 7.24.7
|
||||
"@mui/utils": 5.15.20(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/utils": 5.16.0(@types/react@18.3.3)(react@18.3.1)
|
||||
prop-types: 15.8.1
|
||||
react: 18.3.1
|
||||
optionalDependencies:
|
||||
@@ -5679,13 +5688,13 @@ snapshots:
|
||||
"@emotion/react": 11.11.4(@types/react@18.3.3)(react@18.3.1)
|
||||
"@emotion/styled": 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
|
||||
"@mui/system@5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)":
|
||||
"@mui/system@5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)":
|
||||
dependencies:
|
||||
"@babel/runtime": 7.24.7
|
||||
"@mui/private-theming": 5.15.20(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/private-theming": 5.16.0(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/styled-engine": 5.15.14(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(react@18.3.1)
|
||||
"@mui/types": 7.2.14(@types/react@18.3.3)
|
||||
"@mui/utils": 5.15.20(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/utils": 5.16.0(@types/react@18.3.3)(react@18.3.1)
|
||||
clsx: 2.1.1
|
||||
csstype: 3.1.3
|
||||
prop-types: 15.8.1
|
||||
@@ -5699,7 +5708,7 @@ snapshots:
|
||||
optionalDependencies:
|
||||
"@types/react": 18.3.3
|
||||
|
||||
"@mui/utils@5.15.20(@types/react@18.3.3)(react@18.3.1)":
|
||||
"@mui/utils@5.16.0(@types/react@18.3.3)(react@18.3.1)":
|
||||
dependencies:
|
||||
"@babel/runtime": 7.24.7
|
||||
"@types/prop-types": 15.7.12
|
||||
@@ -5709,12 +5718,13 @@ snapshots:
|
||||
optionalDependencies:
|
||||
"@types/react": 18.3.3
|
||||
|
||||
"@mui/x-data-grid@7.8.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)":
|
||||
"@mui/x-data-grid@7.9.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)":
|
||||
dependencies:
|
||||
"@babel/runtime": 7.24.7
|
||||
"@mui/material": 5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@mui/system": 5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/utils": 5.15.20(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/material": 5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@mui/system": 5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/utils": 5.16.0(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/x-internals": 7.9.0(@types/react@18.3.3)(react@18.3.1)
|
||||
clsx: 2.1.1
|
||||
prop-types: 15.8.1
|
||||
react: 18.3.1
|
||||
@@ -5725,15 +5735,23 @@ snapshots:
|
||||
- "@emotion/styled"
|
||||
- "@types/react"
|
||||
|
||||
"@mui/x-tree-view@6.0.0-alpha.1(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/base@5.0.0-beta.20(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)":
|
||||
"@mui/x-internals@7.9.0(@types/react@18.3.3)(react@18.3.1)":
|
||||
dependencies:
|
||||
"@babel/runtime": 7.24.7
|
||||
"@mui/utils": 5.16.0(@types/react@18.3.3)(react@18.3.1)
|
||||
react: 18.3.1
|
||||
transitivePeerDependencies:
|
||||
- "@types/react"
|
||||
|
||||
"@mui/x-tree-view@6.0.0-alpha.1(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/base@5.0.0-beta.20(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/material@5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)":
|
||||
dependencies:
|
||||
"@babel/runtime": 7.24.7
|
||||
"@emotion/react": 11.11.4(@types/react@18.3.3)(react@18.3.1)
|
||||
"@emotion/styled": 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/base": 5.0.0-beta.20(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@mui/material": 5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@mui/system": 5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/utils": 5.15.20(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/material": 5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
"@mui/system": 5.16.0(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)
|
||||
"@mui/utils": 5.16.0(@types/react@18.3.3)(react@18.3.1)
|
||||
"@types/react-transition-group": 4.4.10
|
||||
clsx: 2.1.1
|
||||
prop-types: 15.8.1
|
||||
@@ -6019,7 +6037,7 @@ snapshots:
|
||||
|
||||
"@types/fs-extra@9.0.13":
|
||||
dependencies:
|
||||
"@types/node": 20.14.9
|
||||
"@types/node": 20.14.10
|
||||
|
||||
"@types/hast@3.0.4":
|
||||
dependencies:
|
||||
@@ -6043,7 +6061,7 @@ snapshots:
|
||||
|
||||
"@types/ms@0.7.34": {}
|
||||
|
||||
"@types/node@20.14.9":
|
||||
"@types/node@20.14.10":
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
|
||||
@@ -6070,7 +6088,7 @@ snapshots:
|
||||
|
||||
"@ungap/structured-clone@1.2.0": {}
|
||||
|
||||
"@vitejs/plugin-legacy@5.4.1(terser@5.31.1)(vite@5.3.3(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.1))":
|
||||
"@vitejs/plugin-legacy@5.4.1(terser@5.31.1)(vite@5.3.3(@types/node@20.14.10)(sass@1.77.6)(terser@5.31.1))":
|
||||
dependencies:
|
||||
"@babel/core": 7.24.7
|
||||
"@babel/preset-env": 7.24.7(@babel/core@7.24.7)
|
||||
@@ -6081,18 +6099,18 @@ snapshots:
|
||||
regenerator-runtime: 0.14.1
|
||||
systemjs: 6.15.1
|
||||
terser: 5.31.1
|
||||
vite: 5.3.3(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.1)
|
||||
vite: 5.3.3(@types/node@20.14.10)(sass@1.77.6)(terser@5.31.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
"@vitejs/plugin-react@4.3.1(vite@5.3.3(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.1))":
|
||||
"@vitejs/plugin-react@4.3.1(vite@5.3.3(@types/node@20.14.10)(sass@1.77.6)(terser@5.31.1))":
|
||||
dependencies:
|
||||
"@babel/core": 7.24.7
|
||||
"@babel/plugin-transform-react-jsx-self": 7.24.7(@babel/core@7.24.7)
|
||||
"@babel/plugin-transform-react-jsx-source": 7.24.7(@babel/core@7.24.7)
|
||||
"@types/babel__core": 7.20.5
|
||||
react-refresh: 0.14.2
|
||||
vite: 5.3.3(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.1)
|
||||
vite: 5.3.3(@types/node@20.14.10)(sass@1.77.6)(terser@5.31.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -6188,7 +6206,7 @@ snapshots:
|
||||
browserslist@4.23.1:
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001640
|
||||
electron-to-chromium: 1.4.816
|
||||
electron-to-chromium: 1.4.818
|
||||
node-releases: 2.0.14
|
||||
update-browserslist-db: 1.1.0(browserslist@4.23.1)
|
||||
|
||||
@@ -6321,7 +6339,7 @@ snapshots:
|
||||
no-case: 3.0.4
|
||||
tslib: 2.6.3
|
||||
|
||||
electron-to-chromium@1.4.816: {}
|
||||
electron-to-chromium@1.4.818: {}
|
||||
|
||||
end-of-stream@1.4.4:
|
||||
dependencies:
|
||||
@@ -7393,24 +7411,24 @@ snapshots:
|
||||
dependencies:
|
||||
monaco-editor: 0.49.0
|
||||
|
||||
vite-plugin-svgr@4.2.0(rollup@4.18.0)(typescript@5.5.3)(vite@5.3.3(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.1)):
|
||||
vite-plugin-svgr@4.2.0(rollup@4.18.0)(typescript@5.5.3)(vite@5.3.3(@types/node@20.14.10)(sass@1.77.6)(terser@5.31.1)):
|
||||
dependencies:
|
||||
"@rollup/pluginutils": 5.1.0(rollup@4.18.0)
|
||||
"@svgr/core": 8.1.0(typescript@5.5.3)
|
||||
"@svgr/plugin-jsx": 8.1.0(@svgr/core@8.1.0(typescript@5.5.3))
|
||||
vite: 5.3.3(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.1)
|
||||
vite: 5.3.3(@types/node@20.14.10)(sass@1.77.6)(terser@5.31.1)
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite@5.3.3(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.1):
|
||||
vite@5.3.3(@types/node@20.14.10)(sass@1.77.6)(terser@5.31.1):
|
||||
dependencies:
|
||||
esbuild: 0.21.5
|
||||
postcss: 8.4.39
|
||||
rollup: 4.18.0
|
||||
optionalDependencies:
|
||||
"@types/node": 20.14.9
|
||||
"@types/node": 20.14.10
|
||||
fsevents: 2.3.3
|
||||
sass: 1.77.6
|
||||
terser: 5.31.1
|
||||
|
||||
Generated
+259
-230
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "clash-verge"
|
||||
version = "1.7.2"
|
||||
version = "1.7.3"
|
||||
description = "clash verge"
|
||||
authors = ["zzzgydi", "wonfen", "MystiPanda"]
|
||||
license = "GPL-3.0-only"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"package": {
|
||||
"productName": "Clash Verge",
|
||||
"version": "1.7.2"
|
||||
"version": "1.7.3"
|
||||
},
|
||||
"build": {
|
||||
"distDir": "../dist",
|
||||
|
||||
@@ -137,7 +137,7 @@ export const GroupItem = (props: Props) => {
|
||||
);
|
||||
};
|
||||
|
||||
const StyledPrimary = styled("span")`
|
||||
const StyledPrimary = styled("div")`
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
line-height: 1.5;
|
||||
|
||||
@@ -78,10 +78,18 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
const [appendSeq, setAppendSeq] = useState<IProxyGroupConfig[]>([]);
|
||||
const [deleteSeq, setDeleteSeq] = useState<string[]>([]);
|
||||
|
||||
const filteredPrependSeq = useMemo(
|
||||
() => prependSeq.filter((group) => match(group.name)),
|
||||
[prependSeq, match]
|
||||
);
|
||||
const filteredGroupList = useMemo(
|
||||
() => groupList.filter((group) => match(group.name)),
|
||||
[groupList, match]
|
||||
);
|
||||
const filteredAppendSeq = useMemo(
|
||||
() => appendSeq.filter((group) => match(group.name)),
|
||||
[appendSeq, match]
|
||||
);
|
||||
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor),
|
||||
@@ -376,6 +384,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
}}
|
||||
multiple
|
||||
options={proxyPolicyList}
|
||||
disableCloseOnSelect
|
||||
onChange={(_, value) => value && field.onChange(value)}
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
/>
|
||||
@@ -393,6 +402,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
sx={{ width: "calc(100% - 150px)" }}
|
||||
multiple
|
||||
options={proxyProviderList}
|
||||
disableCloseOnSelect
|
||||
onChange={(_, value) => value && field.onChange(value)}
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
/>
|
||||
@@ -541,23 +551,33 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Autocomplete
|
||||
multiple
|
||||
options={[
|
||||
"ss",
|
||||
"ssr",
|
||||
"direct",
|
||||
"dns",
|
||||
"snell",
|
||||
"http",
|
||||
"trojan",
|
||||
"hysteria",
|
||||
"hysteria2",
|
||||
"tuic",
|
||||
"wireguard",
|
||||
"ssh",
|
||||
"socks5",
|
||||
"vmess",
|
||||
"vless",
|
||||
"Direct",
|
||||
"Reject",
|
||||
"RejectDrop",
|
||||
"Compatible",
|
||||
"Pass",
|
||||
"Dns",
|
||||
"Shadowsocks",
|
||||
"ShadowsocksR",
|
||||
"Snell",
|
||||
"Socks5",
|
||||
"Http",
|
||||
"Vmess",
|
||||
"Vless",
|
||||
"Trojan",
|
||||
"Hysteria",
|
||||
"Hysteria2",
|
||||
"WireGuard",
|
||||
"Tuic",
|
||||
"Relay",
|
||||
"Selector",
|
||||
"Fallback",
|
||||
"URLTest",
|
||||
"LoadBalance",
|
||||
"Ssh",
|
||||
]}
|
||||
size="small"
|
||||
disableCloseOnSelect
|
||||
sx={{ width: "calc(100% - 150px)" }}
|
||||
value={field.value?.split("|")}
|
||||
onChange={(_, value) => {
|
||||
@@ -576,7 +596,6 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<ListItemText primary={t("Expected Status")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
type="number"
|
||||
size="small"
|
||||
sx={{ width: "calc(100% - 150px)" }}
|
||||
onChange={(e) => {
|
||||
@@ -705,13 +724,13 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
style={{ height: "calc(100% - 24px)", marginTop: "8px" }}
|
||||
totalCount={
|
||||
filteredGroupList.length +
|
||||
(prependSeq.length > 0 ? 1 : 0) +
|
||||
(appendSeq.length > 0 ? 1 : 0)
|
||||
(filteredPrependSeq.length > 0 ? 1 : 0) +
|
||||
(filteredAppendSeq.length > 0 ? 1 : 0)
|
||||
}
|
||||
increaseViewportBy={256}
|
||||
itemContent={(index) => {
|
||||
let shift = prependSeq.length > 0 ? 1 : 0;
|
||||
if (prependSeq.length > 0 && index === 0) {
|
||||
let shift = filteredPrependSeq.length > 0 ? 1 : 0;
|
||||
if (filteredPrependSeq.length > 0 && index === 0) {
|
||||
return (
|
||||
<DndContext
|
||||
sensors={sensors}
|
||||
@@ -719,11 +738,11 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
onDragEnd={onPrependDragEnd}
|
||||
>
|
||||
<SortableContext
|
||||
items={prependSeq.map((x) => {
|
||||
items={filteredPrependSeq.map((x) => {
|
||||
return x.name;
|
||||
})}
|
||||
>
|
||||
{prependSeq.map((item, index) => {
|
||||
{filteredPrependSeq.map((item, index) => {
|
||||
return (
|
||||
<GroupItem
|
||||
key={`${item.name}-${index}`}
|
||||
@@ -779,11 +798,11 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
onDragEnd={onAppendDragEnd}
|
||||
>
|
||||
<SortableContext
|
||||
items={appendSeq.map((x) => {
|
||||
items={filteredAppendSeq.map((x) => {
|
||||
return x.name;
|
||||
})}
|
||||
>
|
||||
{appendSeq.map((item, index) => {
|
||||
{filteredAppendSeq.map((item, index) => {
|
||||
return (
|
||||
<GroupItem
|
||||
key={`${item.name}-${index}`}
|
||||
|
||||
@@ -61,10 +61,18 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
const [appendSeq, setAppendSeq] = useState<IProxyConfig[]>([]);
|
||||
const [deleteSeq, setDeleteSeq] = useState<string[]>([]);
|
||||
|
||||
const filteredPrependSeq = useMemo(
|
||||
() => prependSeq.filter((proxy) => match(proxy.name)),
|
||||
[prependSeq, match]
|
||||
);
|
||||
const filteredProxyList = useMemo(
|
||||
() => proxyList.filter((proxy) => match(proxy.name)),
|
||||
[proxyList, match]
|
||||
);
|
||||
const filteredAppendSeq = useMemo(
|
||||
() => appendSeq.filter((proxy) => match(proxy.name)),
|
||||
[appendSeq, match]
|
||||
);
|
||||
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor),
|
||||
@@ -119,7 +127,31 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleParse = () => {
|
||||
let proxies = [] as IProxyConfig[];
|
||||
let names: string[] = [];
|
||||
let uris = "";
|
||||
try {
|
||||
uris = atob(proxyUri);
|
||||
} catch {
|
||||
uris = proxyUri;
|
||||
}
|
||||
uris
|
||||
.trim()
|
||||
.split("\n")
|
||||
.forEach((uri) => {
|
||||
try {
|
||||
let proxy = parseUri(uri.trim());
|
||||
if (!names.includes(proxy.name)) {
|
||||
proxies.push(proxy);
|
||||
names.push(proxy.name);
|
||||
}
|
||||
} catch (err: any) {
|
||||
Notice.error(err.message || err.toString());
|
||||
}
|
||||
});
|
||||
return proxies;
|
||||
};
|
||||
const fetchProfile = async () => {
|
||||
let data = await readProfileFile(profileUid);
|
||||
|
||||
@@ -228,7 +260,6 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
placeholder={t("Use newlines for multiple uri")}
|
||||
fullWidth
|
||||
rows={9}
|
||||
sx={{ height: "100px" }}
|
||||
multiline
|
||||
size="small"
|
||||
onChange={(e) => setProxyUri(e.target.value)}
|
||||
@@ -240,18 +271,7 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
fullWidth
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
let proxies = [] as IProxyConfig[];
|
||||
proxyUri
|
||||
.trim()
|
||||
.split("\n")
|
||||
.forEach((uri) => {
|
||||
try {
|
||||
let proxy = parseUri(uri.trim());
|
||||
proxies.push(proxy);
|
||||
} catch (err: any) {
|
||||
Notice.error(err.message || err.toString());
|
||||
}
|
||||
});
|
||||
let proxies = handleParse();
|
||||
setPrependSeq([...prependSeq, ...proxies]);
|
||||
}}
|
||||
>
|
||||
@@ -263,18 +283,7 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
fullWidth
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
let proxies = [] as IProxyConfig[];
|
||||
proxyUri
|
||||
.trim()
|
||||
.split("\n")
|
||||
.forEach((uri) => {
|
||||
try {
|
||||
let proxy = parseUri(uri.trim());
|
||||
proxies.push(proxy);
|
||||
} catch (err: any) {
|
||||
Notice.error(err.message || err.toString());
|
||||
}
|
||||
});
|
||||
let proxies = handleParse();
|
||||
setAppendSeq([...appendSeq, ...proxies]);
|
||||
}}
|
||||
>
|
||||
@@ -297,13 +306,13 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
style={{ height: "calc(100% - 24px)", marginTop: "8px" }}
|
||||
totalCount={
|
||||
filteredProxyList.length +
|
||||
(prependSeq.length > 0 ? 1 : 0) +
|
||||
(appendSeq.length > 0 ? 1 : 0)
|
||||
(filteredPrependSeq.length > 0 ? 1 : 0) +
|
||||
(filteredAppendSeq.length > 0 ? 1 : 0)
|
||||
}
|
||||
increaseViewportBy={256}
|
||||
itemContent={(index) => {
|
||||
let shift = prependSeq.length > 0 ? 1 : 0;
|
||||
if (prependSeq.length > 0 && index === 0) {
|
||||
let shift = filteredPrependSeq.length > 0 ? 1 : 0;
|
||||
if (filteredPrependSeq.length > 0 && index === 0) {
|
||||
return (
|
||||
<DndContext
|
||||
sensors={sensors}
|
||||
@@ -311,11 +320,11 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
onDragEnd={onPrependDragEnd}
|
||||
>
|
||||
<SortableContext
|
||||
items={prependSeq.map((x) => {
|
||||
items={filteredPrependSeq.map((x) => {
|
||||
return x.name;
|
||||
})}
|
||||
>
|
||||
{prependSeq.map((item, index) => {
|
||||
{filteredPrependSeq.map((item, index) => {
|
||||
return (
|
||||
<ProxyItem
|
||||
key={`${item.name}-${index}`}
|
||||
@@ -371,11 +380,11 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
onDragEnd={onAppendDragEnd}
|
||||
>
|
||||
<SortableContext
|
||||
items={appendSeq.map((x) => {
|
||||
items={filteredAppendSeq.map((x) => {
|
||||
return x.name;
|
||||
})}
|
||||
>
|
||||
{appendSeq.map((item, index) => {
|
||||
{filteredAppendSeq.map((item, index) => {
|
||||
return (
|
||||
<ProxyItem
|
||||
key={`${item.name}-${index}`}
|
||||
|
||||
@@ -90,7 +90,7 @@ export const ProxyItem = (props: Props) => {
|
||||
);
|
||||
};
|
||||
|
||||
const StyledPrimary = styled("span")`
|
||||
const StyledPrimary = styled("div")`
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
line-height: 1.5;
|
||||
|
||||
@@ -18,7 +18,12 @@ interface Props {
|
||||
export const RuleItem = (props: Props) => {
|
||||
let { type, ruleRaw, onDelete } = props;
|
||||
const sortable = type === "prepend" || type === "append";
|
||||
const rule = ruleRaw.replace(",no-resolve", "").split(",");
|
||||
const rule = ruleRaw.replace(",no-resolve", "");
|
||||
|
||||
const ruleType = rule.match(/^[^,]+/)?.[0] ?? "";
|
||||
const proxyPolicy = rule.match(/[^,]+$/)?.[0] ?? "";
|
||||
const ruleContent = rule.slice(ruleType.length + 1, -proxyPolicy.length - 1);
|
||||
|
||||
const { attributes, listeners, setNodeRef, transform, transition } = sortable
|
||||
? useSortable({ id: ruleRaw })
|
||||
: {
|
||||
@@ -56,7 +61,7 @@ export const RuleItem = (props: Props) => {
|
||||
<StyledPrimary
|
||||
sx={{ textDecoration: type === "delete" ? "line-through" : "" }}
|
||||
>
|
||||
{rule.length === 3 ? rule[1] : "-"}
|
||||
{ruleContent || "-"}
|
||||
</StyledPrimary>
|
||||
}
|
||||
secondary={
|
||||
@@ -70,10 +75,10 @@ export const RuleItem = (props: Props) => {
|
||||
}}
|
||||
>
|
||||
<Box sx={{ marginTop: "2px" }}>
|
||||
<StyledTypeBox>{rule[0]}</StyledTypeBox>
|
||||
<StyledTypeBox>{ruleType}</StyledTypeBox>
|
||||
</Box>
|
||||
<StyledSubtitle sx={{ color: "text.secondary" }}>
|
||||
{rule.length === 3 ? rule[2] : rule[1]}
|
||||
{proxyPolicy}
|
||||
</StyledSubtitle>
|
||||
</ListItemTextChild>
|
||||
}
|
||||
@@ -92,7 +97,7 @@ export const RuleItem = (props: Props) => {
|
||||
);
|
||||
};
|
||||
|
||||
const StyledPrimary = styled("span")`
|
||||
const StyledPrimary = styled("div")`
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
line-height: 1.5;
|
||||
|
||||
@@ -254,10 +254,18 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
const [appendSeq, setAppendSeq] = useState<string[]>([]);
|
||||
const [deleteSeq, setDeleteSeq] = useState<string[]>([]);
|
||||
|
||||
const filteredPrependSeq = useMemo(
|
||||
() => prependSeq.filter((rule) => match(rule)),
|
||||
[prependSeq, match]
|
||||
);
|
||||
const filteredRuleList = useMemo(
|
||||
() => ruleList.filter((rule) => match(rule)),
|
||||
[ruleList, match]
|
||||
);
|
||||
const filteredAppendSeq = useMemo(
|
||||
() => appendSeq.filter((rule) => match(rule)),
|
||||
[appendSeq, match]
|
||||
);
|
||||
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor),
|
||||
@@ -573,13 +581,13 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
style={{ height: "calc(100% - 24px)", marginTop: "8px" }}
|
||||
totalCount={
|
||||
filteredRuleList.length +
|
||||
(prependSeq.length > 0 ? 1 : 0) +
|
||||
(appendSeq.length > 0 ? 1 : 0)
|
||||
(filteredPrependSeq.length > 0 ? 1 : 0) +
|
||||
(filteredAppendSeq.length > 0 ? 1 : 0)
|
||||
}
|
||||
increaseViewportBy={256}
|
||||
itemContent={(index) => {
|
||||
let shift = prependSeq.length > 0 ? 1 : 0;
|
||||
if (prependSeq.length > 0 && index === 0) {
|
||||
let shift = filteredPrependSeq.length > 0 ? 1 : 0;
|
||||
if (filteredPrependSeq.length > 0 && index === 0) {
|
||||
return (
|
||||
<DndContext
|
||||
sensors={sensors}
|
||||
@@ -587,11 +595,11 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
onDragEnd={onPrependDragEnd}
|
||||
>
|
||||
<SortableContext
|
||||
items={prependSeq.map((x) => {
|
||||
items={filteredPrependSeq.map((x) => {
|
||||
return x;
|
||||
})}
|
||||
>
|
||||
{prependSeq.map((item, index) => {
|
||||
{filteredPrependSeq.map((item, index) => {
|
||||
return (
|
||||
<RuleItem
|
||||
key={`${item}-${index}`}
|
||||
@@ -643,11 +651,11 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
onDragEnd={onAppendDragEnd}
|
||||
>
|
||||
<SortableContext
|
||||
items={appendSeq.map((x) => {
|
||||
items={filteredAppendSeq.map((x) => {
|
||||
return x;
|
||||
})}
|
||||
>
|
||||
{appendSeq.map((item, index) => {
|
||||
{filteredAppendSeq.map((item, index) => {
|
||||
return (
|
||||
<RuleItem
|
||||
key={`${item}-${index}`}
|
||||
|
||||
@@ -28,10 +28,10 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
let validReg;
|
||||
if (getSystem() === "windows") {
|
||||
validReg =
|
||||
/^((\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|(\d{1,3}\.){1,3}\d{1,3}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\*|\d{1,3}\.\d{1,3}\.\*|\d{1,3}\.\*|([a-fA-F0-9:]+:+)+[a-fA-F0-9]+|localhost|<local>)(;((\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|(\d{1,3}\.){1,3}\d{1,3}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\*|\d{1,3}\.\d{1,3}\.\*|\d{1,3}\.\*|([a-fA-F0-9:]+:+)+[a-fA-F0-9]+|localhost|<local>))*;?$/;
|
||||
/^((\*\.)?([a-zA-Z0-9-]+\.?)+(local|test|example|invalid|localhost|onion|([a-zA-Z]{2,}))|(\d{1,3}\.){1,3}\d{1,3}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\*|\d{1,3}\.\d{1,3}\.\*|\d{1,3}\.\*|([a-fA-F0-9:]+:+)+[a-fA-F0-9]+|localhost|<local>)(;((\*\.)?([a-zA-Z0-9-]+\.?)+(local|test|example|invalid|localhost|onion|([a-zA-Z]{2,}))|(\d{1,3}\.){1,3}\d{1,3}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\*|\d{1,3}\.\d{1,3}\.\*|\d{1,3}\.\*|([a-fA-F0-9:]+:+)+[a-fA-F0-9]+|localhost|<local>))*;?$/;
|
||||
} else {
|
||||
validReg =
|
||||
/^((\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|(\d{1,3}\.){1,3}\d{1,3}(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\d{1,3}\.\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|([a-fA-F0-9:]+:+)+[a-fA-F0-9]+(\/\d{1,3})?|localhost|<local>)(,((\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|(\d{1,3}\.){1,3}\d{1,3}(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\d{1,3}\.\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|([a-fA-F0-9:]+:+)+[a-fA-F0-9]+(\/\d{1,3})?|localhost|<local>))*,?$/;
|
||||
/^((\*\.)?([a-zA-Z0-9-]+\.?)+(local|test|example|invalid|localhost|onion|([a-zA-Z]{2,}))|(\d{1,3}\.){1,3}\d{1,3}(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\d{1,3}\.\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|([a-fA-F0-9:]+:+)+[a-fA-F0-9]+(\/\d{1,3})?|localhost|<local>)(,((\*\.)?([a-zA-Z0-9-]+\.?)+(local|test|example|invalid|localhost|onion|([a-zA-Z]{2,}))|(\d{1,3}\.){1,3}\d{1,3}(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\d{1,3}\.\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\d{1,3}\.\*(\/\d{1,2}|\/3[0-2])?|\d{1,3}\.\*(\/3[0-2])?|([a-fA-F0-9:]+:+)+[a-fA-F0-9]+(\/\d{1,3})?|localhost|<local>))*,?$/;
|
||||
}
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
+46
-9
@@ -223,7 +223,7 @@ interface IProxyGroupConfig {
|
||||
filter?: string;
|
||||
"exclude-filter"?: string;
|
||||
"exclude-type"?: string;
|
||||
"expected-status"?: number;
|
||||
"expected-status"?: string;
|
||||
hidden?: boolean;
|
||||
icon?: string;
|
||||
}
|
||||
@@ -243,7 +243,7 @@ interface HttpOptions {
|
||||
method?: string;
|
||||
path?: string[];
|
||||
headers?: {
|
||||
[key: string]: string;
|
||||
[key: string]: string[];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -262,7 +262,38 @@ interface RealityOptions {
|
||||
}
|
||||
|
||||
type NetworkType = "ws" | "http" | "h2" | "grpc";
|
||||
|
||||
type CipherType =
|
||||
| "none"
|
||||
| "auto"
|
||||
| "dummy"
|
||||
| "aes-128-gcm"
|
||||
| "aes-192-gcm"
|
||||
| "aes-256-gcm"
|
||||
| "lea-128-gcm"
|
||||
| "lea-192-gcm"
|
||||
| "lea-256-gcm"
|
||||
| "aes-128-gcm-siv"
|
||||
| "aes-256-gcm-siv"
|
||||
| "2022-blake3-aes-128-gcm"
|
||||
| "2022-blake3-aes-256-gcm"
|
||||
| "aes-128-cfb"
|
||||
| "aes-192-cfb"
|
||||
| "aes-256-cfb"
|
||||
| "aes-128-ctr"
|
||||
| "aes-192-ctr"
|
||||
| "aes-256-ctr"
|
||||
| "chacha20"
|
||||
| "chacha20-ietf"
|
||||
| "chacha20-ietf-poly1305"
|
||||
| "2022-blake3-chacha20-poly1305"
|
||||
| "rabbit128-poly1305"
|
||||
| "xchacha20-ietf-poly1305"
|
||||
| "xchacha20"
|
||||
| "aegis-128l"
|
||||
| "aegis-256"
|
||||
| "aez-384"
|
||||
| "deoxys-ii-256-128"
|
||||
| "rc4-md5";
|
||||
// base
|
||||
interface IProxyBaseConfig {
|
||||
tfo?: boolean;
|
||||
@@ -294,7 +325,9 @@ interface IProxyHttpConfig extends IProxyBaseConfig {
|
||||
sni?: string;
|
||||
"skip-cert-verify"?: boolean;
|
||||
fingerprint?: string;
|
||||
headers?: {};
|
||||
headers?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
}
|
||||
// socks5
|
||||
interface IProxySocks5Config extends IProxyBaseConfig {
|
||||
@@ -399,7 +432,9 @@ interface IProxyVlessConfig extends IProxyBaseConfig {
|
||||
"grpc-opts"?: GrpcOptions;
|
||||
"ws-opts"?: WsOptions;
|
||||
"ws-path"?: string;
|
||||
"ws-headers"?: {};
|
||||
"ws-headers"?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
"skip-cert-verify"?: boolean;
|
||||
fingerprint?: string;
|
||||
servername?: string;
|
||||
@@ -413,7 +448,7 @@ interface IProxyVmessConfig extends IProxyBaseConfig {
|
||||
port?: number;
|
||||
uuid?: string;
|
||||
alterId?: number;
|
||||
cipher?: string;
|
||||
cipher?: CipherType;
|
||||
udp?: boolean;
|
||||
network?: NetworkType;
|
||||
tls?: boolean;
|
||||
@@ -516,7 +551,7 @@ interface IProxyShadowsocksConfig extends IProxyBaseConfig {
|
||||
server?: string;
|
||||
port?: number;
|
||||
password?: string;
|
||||
cipher?: string;
|
||||
cipher?: CipherType;
|
||||
udp?: boolean;
|
||||
plugin?: "obfs" | "v2ray-plugin" | "shadow-tls" | "restls";
|
||||
"plugin-opts"?: {
|
||||
@@ -526,7 +561,9 @@ interface IProxyShadowsocksConfig extends IProxyBaseConfig {
|
||||
path?: string;
|
||||
tls?: string;
|
||||
fingerprint?: string;
|
||||
headers?: {};
|
||||
headers?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
"skip-cert-verify"?: boolean;
|
||||
version?: number;
|
||||
mux?: boolean;
|
||||
@@ -546,7 +583,7 @@ interface IProxyshadowsocksRConfig extends IProxyBaseConfig {
|
||||
server?: string;
|
||||
port?: number;
|
||||
password?: string;
|
||||
cipher?: string;
|
||||
cipher?: CipherType;
|
||||
obfs?: string;
|
||||
"obfs-param"?: string;
|
||||
protocol?: string;
|
||||
|
||||
@@ -80,10 +80,83 @@ function decodeBase64OrOriginal(str: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
function getCipher(str: string | undefined) {
|
||||
switch (str) {
|
||||
case "none":
|
||||
return "none";
|
||||
case "auto":
|
||||
return "auto";
|
||||
case "dummy":
|
||||
return "dummy";
|
||||
case "aes-128-gcm":
|
||||
return "aes-128-gcm";
|
||||
case "aes-192-gcm":
|
||||
return "aes-192-gcm";
|
||||
case "aes-256-gcm":
|
||||
return "aes-256-gcm";
|
||||
case "lea-128-gcm":
|
||||
return "lea-128-gcm";
|
||||
case "lea-192-gcm":
|
||||
return "lea-192-gcm";
|
||||
case "lea-256-gcm":
|
||||
return "lea-256-gcm";
|
||||
case "aes-128-gcm-siv":
|
||||
return "aes-128-gcm-siv";
|
||||
case "aes-256-gcm-siv":
|
||||
return "aes-256-gcm-siv";
|
||||
case "2022-blake3-aes-128-gcm":
|
||||
return "2022-blake3-aes-128-gcm";
|
||||
case "2022-blake3-aes-256-gcm":
|
||||
return "2022-blake3-aes-256-gcm";
|
||||
case "aes-128-cfb":
|
||||
return "aes-128-cfb";
|
||||
case "aes-192-cfb":
|
||||
return "aes-192-cfb";
|
||||
case "aes-256-cfb":
|
||||
return "aes-256-cfb";
|
||||
case "aes-128-ctr":
|
||||
return "aes-128-ctr";
|
||||
case "aes-192-ctr":
|
||||
return "aes-192-ctr";
|
||||
case "aes-256-ctr":
|
||||
return "aes-256-ctr";
|
||||
case "chacha20":
|
||||
return "chacha20";
|
||||
case "chacha20-poly1305":
|
||||
return "chacha20-ietf-poly1305";
|
||||
case "chacha20-ietf":
|
||||
return "chacha20-ietf";
|
||||
case "chacha20-ietf-poly1305":
|
||||
return "chacha20-ietf-poly1305";
|
||||
case "2022-blake3-chacha20-poly1305":
|
||||
return "2022-blake3-chacha20-poly1305";
|
||||
case "rabbit128-poly1305":
|
||||
return "rabbit128-poly1305";
|
||||
case "xchacha20-ietf-poly1305":
|
||||
return "xchacha20-ietf-poly1305";
|
||||
case "xchacha20":
|
||||
return "xchacha20";
|
||||
case "aegis-128l":
|
||||
return "aegis-128l";
|
||||
case "aegis-256":
|
||||
return "aegis-256";
|
||||
case "aez-384":
|
||||
return "aez-384";
|
||||
case "deoxys-ii-256-128":
|
||||
return "deoxys-ii-256-128";
|
||||
case "rc4-md5":
|
||||
return "rc4-md5";
|
||||
case undefined:
|
||||
return "none";
|
||||
default:
|
||||
return "auto";
|
||||
}
|
||||
}
|
||||
|
||||
function URI_SS(line: string): IProxyShadowsocksConfig {
|
||||
// parse url
|
||||
let content = line.split("ss://")[1];
|
||||
content = decodeBase64OrOriginal(content);
|
||||
|
||||
const proxy: IProxyShadowsocksConfig = {
|
||||
name: decodeURIComponent(line.split("#")[1]).trim(),
|
||||
type: "ss",
|
||||
@@ -125,7 +198,7 @@ function URI_SS(line: string): IProxyShadowsocksConfig {
|
||||
`${serverAndPort?.substring(portIdx + 1)}`.match(/\d+/)?.[0] ?? ""
|
||||
);
|
||||
const userInfo = userInfoStr.match(/(^.*?):(.*$)/);
|
||||
proxy.cipher = userInfo?.[1];
|
||||
proxy.cipher = getCipher(userInfo?.[1]);
|
||||
proxy.password = userInfo?.[2];
|
||||
|
||||
// handle obfs
|
||||
@@ -172,7 +245,7 @@ function URI_SS(line: string): IProxyShadowsocksConfig {
|
||||
|
||||
function URI_SSR(line: string): IProxyshadowsocksRConfig {
|
||||
line = decodeBase64OrOriginal(line.split("ssr://")[1]);
|
||||
line = decodeBase64OrOriginal(line);
|
||||
|
||||
// handle IPV6 & IPV4 format
|
||||
let splitIdx = line.indexOf(":origin");
|
||||
if (splitIdx === -1) {
|
||||
@@ -194,7 +267,7 @@ function URI_SSR(line: string): IProxyshadowsocksRConfig {
|
||||
server,
|
||||
port,
|
||||
protocol: params[0],
|
||||
cipher: params[1],
|
||||
cipher: getCipher(params[1]),
|
||||
obfs: params[2],
|
||||
password: decodeBase64OrOriginal(params[3]),
|
||||
};
|
||||
@@ -243,7 +316,7 @@ function URI_VMESS(line: string): IProxyVmessConfig {
|
||||
type: "vmess",
|
||||
server: partitions[1],
|
||||
port: parseInt(partitions[2], 10),
|
||||
cipher: getIfNotBlank(partitions[3], "auto"),
|
||||
cipher: getCipher(getIfNotBlank(partitions[3], "auto")),
|
||||
uuid: partitions[4].match(/^"(.*)"$/)?.[1] || "",
|
||||
tls: params.obfs === "wss",
|
||||
udp: getIfPresent(params["udp-relay"]),
|
||||
@@ -320,7 +393,7 @@ function URI_VMESS(line: string): IProxyVmessConfig {
|
||||
type: "vmess",
|
||||
server,
|
||||
port,
|
||||
cipher: getIfPresent(params.scy, "auto"),
|
||||
cipher: getCipher(getIfPresent(params.scy, "auto")),
|
||||
uuid: params.id,
|
||||
tls: ["tls", true, 1, "1"].includes(params.tls),
|
||||
"skip-cert-verify": isPresent(params.verify_cert)
|
||||
@@ -411,7 +484,6 @@ function URI_VMESS(line: string): IProxyVmessConfig {
|
||||
|
||||
function URI_VLESS(line: string): IProxyVlessConfig {
|
||||
line = line.split("vless://")[1];
|
||||
line = decodeBase64OrOriginal(line);
|
||||
let isShadowrocket;
|
||||
let parsed = /^(.*?)@(.*?):(\d+)\/?(\?(.*?))?(?:#(.*?))?$/.exec(line)!;
|
||||
if (!parsed) {
|
||||
@@ -578,7 +650,6 @@ function URI_Trojan(line: string): IProxyTrojanConfig {
|
||||
|
||||
function URI_Hysteria2(line: string): IProxyHysteria2Config {
|
||||
line = line.split(/(hysteria2|hy2):\/\//)[2];
|
||||
line = decodeBase64OrOriginal(line);
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
let [__, password, server, ___, port, ____, addons = "", name] =
|
||||
/^(.*?)@(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line) || [];
|
||||
@@ -627,7 +698,6 @@ function URI_Hysteria2(line: string): IProxyHysteria2Config {
|
||||
|
||||
function URI_Hysteria(line: string): IProxyHysteriaConfig {
|
||||
line = line.split(/(hysteria|hy):\/\//)[2];
|
||||
line = decodeBase64OrOriginal(line);
|
||||
let [__, server, ___, port, ____, addons = "", name] =
|
||||
/^(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line)!;
|
||||
let portNum = parseInt(`${port}`, 10);
|
||||
@@ -723,7 +793,7 @@ function URI_Hysteria(line: string): IProxyHysteriaConfig {
|
||||
|
||||
function URI_TUIC(line: string): IProxyTuicConfig {
|
||||
line = line.split(/tuic:\/\//)[1];
|
||||
line = decodeBase64OrOriginal(line);
|
||||
|
||||
let [__, uuid, password, server, ___, port, ____, addons = "", name] =
|
||||
/^(.*?):(.*?)@(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line) || [];
|
||||
|
||||
@@ -803,7 +873,6 @@ function URI_TUIC(line: string): IProxyTuicConfig {
|
||||
|
||||
function URI_Wireguard(line: string): IProxyWireguardConfig {
|
||||
line = line.split(/(wireguard|wg):\/\//)[2];
|
||||
line = decodeBase64OrOriginal(line);
|
||||
let [__, ___, privateKey, server, ____, port, _____, addons = "", name] =
|
||||
/^((.*?)@)?(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line)!;
|
||||
|
||||
@@ -886,7 +955,6 @@ function URI_Wireguard(line: string): IProxyWireguardConfig {
|
||||
|
||||
function URI_HTTP(line: string): IProxyHttpConfig {
|
||||
line = line.split(/(http|https):\/\//)[2];
|
||||
line = decodeBase64OrOriginal(line);
|
||||
let [__, ___, auth, server, ____, port, _____, addons = "", name] =
|
||||
/^((.*?)@)?(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line)!;
|
||||
|
||||
@@ -951,7 +1019,6 @@ function URI_HTTP(line: string): IProxyHttpConfig {
|
||||
|
||||
function URI_SOCKS(line: string): IProxySocks5Config {
|
||||
line = line.split(/socks5:\/\//)[1];
|
||||
line = decodeBase64OrOriginal(line);
|
||||
let [__, ___, auth, server, ____, port, _____, addons = "", name] =
|
||||
/^((.*?)@)?(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line)!;
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func getRemoteURLContent(url string) ([]byte, error) {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("failed to get remote content -> %s: %s", url, resp.Status)
|
||||
}
|
||||
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"go4.org/netipx"
|
||||
)
|
||||
|
||||
type Container interface {
|
||||
GetEntry(name string) (*Entry, bool)
|
||||
Add(entry *Entry, opts ...IgnoreIPOption) error
|
||||
Remove(entry *Entry, rCase CaseRemove, opts ...IgnoreIPOption) error
|
||||
Loop() <-chan *Entry
|
||||
}
|
||||
|
||||
type container struct {
|
||||
entries map[string]*Entry
|
||||
}
|
||||
|
||||
func NewContainer() Container {
|
||||
return &container{
|
||||
entries: make(map[string]*Entry),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *container) isValid() bool {
|
||||
return c.entries != nil
|
||||
}
|
||||
|
||||
func (c *container) GetEntry(name string) (*Entry, bool) {
|
||||
if !c.isValid() {
|
||||
return nil, false
|
||||
}
|
||||
val, ok := c.entries[strings.ToUpper(strings.TrimSpace(name))]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return val, true
|
||||
}
|
||||
|
||||
func (c *container) Loop() <-chan *Entry {
|
||||
ch := make(chan *Entry, 300)
|
||||
go func() {
|
||||
for _, val := range c.entries {
|
||||
ch <- val
|
||||
}
|
||||
close(ch)
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
func (c *container) Add(entry *Entry, opts ...IgnoreIPOption) error {
|
||||
var ignoreIPType IPType
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
ignoreIPType = opt()
|
||||
}
|
||||
}
|
||||
|
||||
name := entry.GetName()
|
||||
val, found := c.GetEntry(name)
|
||||
|
||||
switch found {
|
||||
case true:
|
||||
var ipv4set, ipv6set *netipx.IPSet
|
||||
var err4, err6 error
|
||||
if entry.hasIPv4Builder() {
|
||||
ipv4set, err4 = entry.ipv4Builder.IPSet()
|
||||
if err4 != nil {
|
||||
return err4
|
||||
}
|
||||
}
|
||||
if entry.hasIPv6Builder() {
|
||||
ipv6set, err6 = entry.ipv6Builder.IPSet()
|
||||
if err6 != nil {
|
||||
return err6
|
||||
}
|
||||
}
|
||||
switch ignoreIPType {
|
||||
case IPv4:
|
||||
if !val.hasIPv6Builder() {
|
||||
val.ipv6Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
val.ipv6Builder.AddSet(ipv6set)
|
||||
case IPv6:
|
||||
if !val.hasIPv4Builder() {
|
||||
val.ipv4Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
val.ipv4Builder.AddSet(ipv4set)
|
||||
default:
|
||||
if !val.hasIPv4Builder() {
|
||||
val.ipv4Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
if !val.hasIPv6Builder() {
|
||||
val.ipv6Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
val.ipv4Builder.AddSet(ipv4set)
|
||||
val.ipv6Builder.AddSet(ipv6set)
|
||||
}
|
||||
|
||||
case false:
|
||||
switch ignoreIPType {
|
||||
case IPv4:
|
||||
entry.ipv4Builder = nil
|
||||
case IPv6:
|
||||
entry.ipv6Builder = nil
|
||||
}
|
||||
c.entries[name] = entry
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *container) Remove(entry *Entry, rCase CaseRemove, opts ...IgnoreIPOption) error {
|
||||
name := entry.GetName()
|
||||
val, found := c.GetEntry(name)
|
||||
if !found {
|
||||
return fmt.Errorf("entry %s not found", name)
|
||||
}
|
||||
|
||||
var ignoreIPType IPType
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
ignoreIPType = opt()
|
||||
}
|
||||
}
|
||||
|
||||
switch rCase {
|
||||
case CaseRemovePrefix:
|
||||
var ipv4set, ipv6set *netipx.IPSet
|
||||
var err4, err6 error
|
||||
if entry.hasIPv4Builder() {
|
||||
ipv4set, err4 = entry.ipv4Builder.IPSet()
|
||||
if err4 != nil {
|
||||
return err4
|
||||
}
|
||||
}
|
||||
if entry.hasIPv6Builder() {
|
||||
ipv6set, err6 = entry.ipv6Builder.IPSet()
|
||||
if err6 != nil {
|
||||
return err6
|
||||
}
|
||||
}
|
||||
|
||||
switch ignoreIPType {
|
||||
case IPv4:
|
||||
if !val.hasIPv6Builder() {
|
||||
val.ipv6Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
val.ipv6Builder.RemoveSet(ipv6set)
|
||||
case IPv6:
|
||||
if !val.hasIPv4Builder() {
|
||||
val.ipv4Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
val.ipv4Builder.RemoveSet(ipv4set)
|
||||
default:
|
||||
if !val.hasIPv4Builder() {
|
||||
val.ipv4Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
if !val.hasIPv6Builder() {
|
||||
val.ipv6Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
val.ipv4Builder.RemoveSet(ipv4set)
|
||||
val.ipv6Builder.RemoveSet(ipv6set)
|
||||
}
|
||||
|
||||
case CaseRemoveEntry:
|
||||
switch ignoreIPType {
|
||||
case IPv4:
|
||||
val.ipv6Builder = nil
|
||||
case IPv6:
|
||||
val.ipv4Builder = nil
|
||||
default:
|
||||
delete(c.entries, name)
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unknown remove case %d", rCase)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -2,8 +2,6 @@ package lib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
@@ -54,17 +52,3 @@ func RegisterOutputConverter(name string, c OutputConverter) error {
|
||||
outputConverterMap[name] = c
|
||||
return nil
|
||||
}
|
||||
|
||||
func getRemoteURLContent(url string) ([]byte, error) {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("failed to get remote content -> %s: %s", url, resp.Status)
|
||||
}
|
||||
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"go4.org/netipx"
|
||||
)
|
||||
|
||||
type Entry struct {
|
||||
name string
|
||||
mu *sync.Mutex
|
||||
ipv4Builder *netipx.IPSetBuilder
|
||||
ipv6Builder *netipx.IPSetBuilder
|
||||
}
|
||||
|
||||
func NewEntry(name string) *Entry {
|
||||
return &Entry{
|
||||
name: strings.ToUpper(strings.TrimSpace(name)),
|
||||
mu: new(sync.Mutex),
|
||||
ipv4Builder: new(netipx.IPSetBuilder),
|
||||
ipv6Builder: new(netipx.IPSetBuilder),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Entry) GetName() string {
|
||||
return e.name
|
||||
}
|
||||
|
||||
func (e *Entry) hasIPv4Builder() bool {
|
||||
return e.ipv4Builder != nil
|
||||
}
|
||||
|
||||
func (e *Entry) hasIPv6Builder() bool {
|
||||
return e.ipv6Builder != nil
|
||||
}
|
||||
|
||||
func (e *Entry) processPrefix(src any) (*netip.Prefix, IPType, error) {
|
||||
switch src := src.(type) {
|
||||
case net.IP:
|
||||
ip, ok := netipx.FromStdIP(src)
|
||||
if !ok {
|
||||
return nil, "", ErrInvalidIP
|
||||
}
|
||||
ip = ip.Unmap()
|
||||
switch {
|
||||
case ip.Is4():
|
||||
prefix := netip.PrefixFrom(ip, 32)
|
||||
return &prefix, IPv4, nil
|
||||
case ip.Is6():
|
||||
prefix := netip.PrefixFrom(ip, 128)
|
||||
return &prefix, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
|
||||
case *net.IPNet:
|
||||
prefix, ok := netipx.FromStdIPNet(src)
|
||||
if !ok {
|
||||
return nil, "", ErrInvalidIPNet
|
||||
}
|
||||
ip := prefix.Addr().Unmap()
|
||||
switch {
|
||||
case ip.Is4():
|
||||
return &prefix, IPv4, nil
|
||||
case ip.Is6():
|
||||
return &prefix, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
|
||||
case netip.Addr:
|
||||
src = src.Unmap()
|
||||
switch {
|
||||
case src.Is4():
|
||||
prefix := netip.PrefixFrom(src, 32)
|
||||
return &prefix, IPv4, nil
|
||||
case src.Is6():
|
||||
prefix := netip.PrefixFrom(src, 128)
|
||||
return &prefix, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
|
||||
case *netip.Addr:
|
||||
*src = (*src).Unmap()
|
||||
switch {
|
||||
case src.Is4():
|
||||
prefix := netip.PrefixFrom(*src, 32)
|
||||
return &prefix, IPv4, nil
|
||||
case src.Is6():
|
||||
prefix := netip.PrefixFrom(*src, 128)
|
||||
return &prefix, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
|
||||
case netip.Prefix:
|
||||
ip := src.Addr()
|
||||
switch {
|
||||
case ip.Is4():
|
||||
prefix, err := ip.Prefix(src.Bits())
|
||||
if err != nil {
|
||||
return nil, "", ErrInvalidPrefix
|
||||
}
|
||||
return &prefix, IPv4, nil
|
||||
case ip.Is4In6():
|
||||
ip = ip.Unmap()
|
||||
bits := src.Bits()
|
||||
if bits < 96 {
|
||||
return nil, "", ErrInvalidPrefix
|
||||
}
|
||||
prefix, err := ip.Prefix(bits - 96)
|
||||
if err != nil {
|
||||
return nil, "", ErrInvalidPrefix
|
||||
}
|
||||
return &prefix, IPv4, nil
|
||||
case ip.Is6():
|
||||
prefix, err := ip.Prefix(src.Bits())
|
||||
if err != nil {
|
||||
return nil, "", ErrInvalidPrefix
|
||||
}
|
||||
return &prefix, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
|
||||
case *netip.Prefix:
|
||||
ip := src.Addr()
|
||||
switch {
|
||||
case ip.Is4():
|
||||
prefix, err := ip.Prefix(src.Bits())
|
||||
if err != nil {
|
||||
return nil, "", ErrInvalidPrefix
|
||||
}
|
||||
return &prefix, IPv4, nil
|
||||
case ip.Is4In6():
|
||||
ip = ip.Unmap()
|
||||
bits := src.Bits()
|
||||
if bits < 96 {
|
||||
return nil, "", ErrInvalidPrefix
|
||||
}
|
||||
prefix, err := ip.Prefix(bits - 96)
|
||||
if err != nil {
|
||||
return nil, "", ErrInvalidPrefix
|
||||
}
|
||||
return &prefix, IPv4, nil
|
||||
case ip.Is6():
|
||||
prefix, err := ip.Prefix(src.Bits())
|
||||
if err != nil {
|
||||
return nil, "", ErrInvalidPrefix
|
||||
}
|
||||
return &prefix, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
|
||||
case string:
|
||||
src, _, _ = strings.Cut(src, "#")
|
||||
src, _, _ = strings.Cut(src, "//")
|
||||
src, _, _ = strings.Cut(src, "/*")
|
||||
src = strings.TrimSpace(src)
|
||||
if src == "" {
|
||||
return nil, "", ErrCommentLine
|
||||
}
|
||||
|
||||
switch strings.Contains(src, "/") {
|
||||
case true: // src is CIDR notation
|
||||
ip, network, err := net.ParseCIDR(src)
|
||||
if err != nil {
|
||||
return nil, "", ErrInvalidCIDR
|
||||
}
|
||||
addr, ok := netipx.FromStdIP(ip)
|
||||
if !ok {
|
||||
return nil, "", ErrInvalidIP
|
||||
}
|
||||
if addr.Unmap().Is4() && strings.Contains(network.String(), "::") { // src is invalid IPv4-mapped IPv6 address
|
||||
return nil, "", ErrInvalidCIDR
|
||||
}
|
||||
prefix, ok := netipx.FromStdIPNet(network)
|
||||
if !ok {
|
||||
return nil, "", ErrInvalidIPNet
|
||||
}
|
||||
|
||||
addr = prefix.Addr().Unmap()
|
||||
switch {
|
||||
case addr.Is4():
|
||||
return &prefix, IPv4, nil
|
||||
case addr.Is6():
|
||||
return &prefix, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
|
||||
case false: // src is IP address
|
||||
ip, err := netip.ParseAddr(src)
|
||||
if err != nil {
|
||||
return nil, "", ErrInvalidIP
|
||||
}
|
||||
ip = ip.Unmap()
|
||||
switch {
|
||||
case ip.Is4():
|
||||
prefix := netip.PrefixFrom(ip, 32)
|
||||
return &prefix, IPv4, nil
|
||||
case ip.Is6():
|
||||
prefix := netip.PrefixFrom(ip, 128)
|
||||
return &prefix, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, "", ErrInvalidPrefixType
|
||||
}
|
||||
|
||||
func (e *Entry) add(prefix *netip.Prefix, ipType IPType) error {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
switch ipType {
|
||||
case IPv4:
|
||||
if !e.hasIPv4Builder() {
|
||||
e.ipv4Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
e.ipv4Builder.AddPrefix(*prefix)
|
||||
case IPv6:
|
||||
if !e.hasIPv6Builder() {
|
||||
e.ipv6Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
e.ipv6Builder.AddPrefix(*prefix)
|
||||
default:
|
||||
return ErrInvalidIPType
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Entry) remove(prefix *netip.Prefix, ipType IPType) error {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
switch ipType {
|
||||
case IPv4:
|
||||
if e.hasIPv4Builder() {
|
||||
e.ipv4Builder.RemovePrefix(*prefix)
|
||||
}
|
||||
case IPv6:
|
||||
if e.hasIPv6Builder() {
|
||||
e.ipv6Builder.RemovePrefix(*prefix)
|
||||
}
|
||||
default:
|
||||
return ErrInvalidIPType
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Entry) AddPrefix(cidr any) error {
|
||||
prefix, ipType, err := e.processPrefix(cidr)
|
||||
if err != nil && err != ErrCommentLine {
|
||||
return err
|
||||
}
|
||||
if err := e.add(prefix, ipType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Entry) RemovePrefix(cidr string) error {
|
||||
prefix, ipType, err := e.processPrefix(cidr)
|
||||
if err != nil && err != ErrCommentLine {
|
||||
return err
|
||||
}
|
||||
if err := e.remove(prefix, ipType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Entry) MarshalText(opts ...IgnoreIPOption) ([]string, error) {
|
||||
var ignoreIPType IPType
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
ignoreIPType = opt()
|
||||
}
|
||||
}
|
||||
disableIPv4, disableIPv6 := false, false
|
||||
switch ignoreIPType {
|
||||
case IPv4:
|
||||
disableIPv4 = true
|
||||
case IPv6:
|
||||
disableIPv6 = true
|
||||
}
|
||||
|
||||
prefixSet := make([]string, 0, 1024)
|
||||
|
||||
if !disableIPv4 && e.hasIPv4Builder() {
|
||||
ipv4set, err := e.ipv4Builder.IPSet()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prefixes := ipv4set.Prefixes()
|
||||
for _, prefix := range prefixes {
|
||||
prefixSet = append(prefixSet, prefix.String())
|
||||
}
|
||||
}
|
||||
|
||||
if !disableIPv6 && e.hasIPv6Builder() {
|
||||
ipv6set, err := e.ipv6Builder.IPSet()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prefixes := ipv6set.Prefixes()
|
||||
for _, prefix := range prefixes {
|
||||
prefixSet = append(prefixSet, prefix.String())
|
||||
}
|
||||
}
|
||||
|
||||
if len(prefixSet) > 0 {
|
||||
return prefixSet, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("entry %s has no prefix", e.GetName())
|
||||
}
|
||||
@@ -10,6 +10,8 @@ var (
|
||||
ErrInvalidIP = errors.New("invalid IP address")
|
||||
ErrInvalidIPLength = errors.New("invalid IP address length")
|
||||
ErrInvalidIPNet = errors.New("invalid IPNet address")
|
||||
ErrInvalidCIDR = errors.New("invalid CIDR")
|
||||
ErrInvalidPrefix = errors.New("invalid prefix")
|
||||
ErrInvalidPrefixType = errors.New("invalid prefix type")
|
||||
ErrCommentLine = errors.New("comment line")
|
||||
)
|
||||
|
||||
+5
-420
@@ -1,16 +1,5 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"go4.org/netipx"
|
||||
)
|
||||
|
||||
const (
|
||||
ActionAdd Action = "add"
|
||||
ActionRemove Action = "remove"
|
||||
@@ -18,6 +7,9 @@ const (
|
||||
|
||||
IPv4 IPType = "ipv4"
|
||||
IPv6 IPType = "ipv6"
|
||||
|
||||
CaseRemovePrefix CaseRemove = 0
|
||||
CaseRemoveEntry CaseRemove = 1
|
||||
)
|
||||
|
||||
var ActionsRegistry = map[Action]bool{
|
||||
@@ -30,6 +22,8 @@ type Action string
|
||||
|
||||
type IPType string
|
||||
|
||||
type CaseRemove int
|
||||
|
||||
type Typer interface {
|
||||
GetType() string
|
||||
}
|
||||
@@ -56,280 +50,6 @@ type OutputConverter interface {
|
||||
Output(Container) error
|
||||
}
|
||||
|
||||
type Entry struct {
|
||||
name string
|
||||
mu *sync.Mutex
|
||||
ipv4Builder *netipx.IPSetBuilder
|
||||
ipv6Builder *netipx.IPSetBuilder
|
||||
}
|
||||
|
||||
func NewEntry(name string) *Entry {
|
||||
return &Entry{
|
||||
name: strings.ToUpper(strings.TrimSpace(name)),
|
||||
mu: new(sync.Mutex),
|
||||
ipv4Builder: new(netipx.IPSetBuilder),
|
||||
ipv6Builder: new(netipx.IPSetBuilder),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Entry) GetName() string {
|
||||
return e.name
|
||||
}
|
||||
|
||||
func (e *Entry) hasIPv4Builder() bool {
|
||||
return e.ipv4Builder != nil
|
||||
}
|
||||
|
||||
func (e *Entry) hasIPv6Builder() bool {
|
||||
return e.ipv6Builder != nil
|
||||
}
|
||||
|
||||
func (e *Entry) processPrefix(src any) (*netip.Prefix, IPType, error) {
|
||||
switch src := src.(type) {
|
||||
case net.IP:
|
||||
ip, ok := netipx.FromStdIP(src)
|
||||
if !ok {
|
||||
return nil, "", ErrInvalidIP
|
||||
}
|
||||
switch {
|
||||
case ip.Is4():
|
||||
prefix := netip.PrefixFrom(ip, 32)
|
||||
return &prefix, IPv4, nil
|
||||
case ip.Is6():
|
||||
prefix := netip.PrefixFrom(ip, 128)
|
||||
return &prefix, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
|
||||
case *net.IPNet:
|
||||
prefix, ok := netipx.FromStdIPNet(src)
|
||||
if !ok {
|
||||
return nil, "", ErrInvalidIPNet
|
||||
}
|
||||
ip := prefix.Addr()
|
||||
switch {
|
||||
case ip.Is4():
|
||||
return &prefix, IPv4, nil
|
||||
case ip.Is6():
|
||||
return &prefix, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
|
||||
case netip.Addr:
|
||||
switch {
|
||||
case src.Is4():
|
||||
prefix := netip.PrefixFrom(src, 32)
|
||||
return &prefix, IPv4, nil
|
||||
case src.Is6():
|
||||
prefix := netip.PrefixFrom(src, 128)
|
||||
return &prefix, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
|
||||
case *netip.Addr:
|
||||
switch {
|
||||
case src.Is4():
|
||||
prefix := netip.PrefixFrom(*src, 32)
|
||||
return &prefix, IPv4, nil
|
||||
case src.Is6():
|
||||
prefix := netip.PrefixFrom(*src, 128)
|
||||
return &prefix, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
|
||||
case netip.Prefix:
|
||||
ip := src.Addr()
|
||||
switch {
|
||||
case ip.Is4():
|
||||
return &src, IPv4, nil
|
||||
case ip.Is6():
|
||||
return &src, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
|
||||
case *netip.Prefix:
|
||||
ip := src.Addr()
|
||||
switch {
|
||||
case ip.Is4():
|
||||
return src, IPv4, nil
|
||||
case ip.Is6():
|
||||
return src, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
|
||||
case string:
|
||||
src, _, _ = strings.Cut(src, "#")
|
||||
src, _, _ = strings.Cut(src, "//")
|
||||
src, _, _ = strings.Cut(src, "/*")
|
||||
src = strings.TrimSpace(src)
|
||||
if src == "" {
|
||||
return nil, "", ErrCommentLine
|
||||
}
|
||||
|
||||
_, network, err := net.ParseCIDR(src)
|
||||
switch err {
|
||||
case nil:
|
||||
prefix, err2 := netip.ParsePrefix(network.String())
|
||||
if err2 != nil {
|
||||
return nil, "", ErrInvalidIPNet
|
||||
}
|
||||
ip := prefix.Addr()
|
||||
switch {
|
||||
case ip.Is4():
|
||||
return &prefix, IPv4, nil
|
||||
case ip.Is6():
|
||||
return &prefix, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
|
||||
default:
|
||||
ip, err := netip.ParseAddr(src)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
switch {
|
||||
case ip.Is4():
|
||||
prefix := netip.PrefixFrom(ip, 32)
|
||||
return &prefix, IPv4, nil
|
||||
case ip.Is4In6():
|
||||
_, network, err2 := net.ParseCIDR(src + "/128")
|
||||
if err2 != nil {
|
||||
return nil, "", ErrInvalidIPNet
|
||||
}
|
||||
prefix, err3 := netip.ParsePrefix(network.String())
|
||||
if err3 != nil {
|
||||
return nil, "", ErrInvalidIPNet
|
||||
}
|
||||
return &prefix, IPv4, nil
|
||||
case ip.Is6():
|
||||
prefix := netip.PrefixFrom(ip, 128)
|
||||
return &prefix, IPv6, nil
|
||||
default:
|
||||
return nil, "", ErrInvalidIPLength
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, "", ErrInvalidPrefixType
|
||||
}
|
||||
|
||||
func (e *Entry) add(prefix *netip.Prefix, ipType IPType) error {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
switch ipType {
|
||||
case IPv4:
|
||||
if !e.hasIPv4Builder() {
|
||||
e.ipv4Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
e.ipv4Builder.AddPrefix(*prefix)
|
||||
case IPv6:
|
||||
if !e.hasIPv6Builder() {
|
||||
e.ipv6Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
e.ipv6Builder.AddPrefix(*prefix)
|
||||
default:
|
||||
return ErrInvalidIPType
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Entry) remove(prefix *netip.Prefix, ipType IPType) error {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
switch ipType {
|
||||
case IPv4:
|
||||
if e.hasIPv4Builder() {
|
||||
e.ipv4Builder.RemovePrefix(*prefix)
|
||||
}
|
||||
case IPv6:
|
||||
if e.hasIPv6Builder() {
|
||||
e.ipv6Builder.RemovePrefix(*prefix)
|
||||
}
|
||||
default:
|
||||
return ErrInvalidIPType
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Entry) AddPrefix(cidr any) error {
|
||||
prefix, ipType, err := e.processPrefix(cidr)
|
||||
if err != nil && err != ErrCommentLine {
|
||||
return err
|
||||
}
|
||||
if err := e.add(prefix, ipType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Entry) RemovePrefix(cidr string) error {
|
||||
prefix, ipType, err := e.processPrefix(cidr)
|
||||
if err != nil && err != ErrCommentLine {
|
||||
return err
|
||||
}
|
||||
if err := e.remove(prefix, ipType); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Entry) MarshalText(opts ...IgnoreIPOption) ([]string, error) {
|
||||
var ignoreIPType IPType
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
ignoreIPType = opt()
|
||||
}
|
||||
}
|
||||
disableIPv4, disableIPv6 := false, false
|
||||
switch ignoreIPType {
|
||||
case IPv4:
|
||||
disableIPv4 = true
|
||||
case IPv6:
|
||||
disableIPv6 = true
|
||||
}
|
||||
|
||||
prefixSet := make([]string, 0, 1024)
|
||||
|
||||
if !disableIPv4 && e.hasIPv4Builder() {
|
||||
ipv4set, err := e.ipv4Builder.IPSet()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prefixes := ipv4set.Prefixes()
|
||||
for _, prefix := range prefixes {
|
||||
prefixSet = append(prefixSet, prefix.String())
|
||||
}
|
||||
}
|
||||
|
||||
if !disableIPv6 && e.hasIPv6Builder() {
|
||||
ipv6set, err := e.ipv6Builder.IPSet()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prefixes := ipv6set.Prefixes()
|
||||
for _, prefix := range prefixes {
|
||||
prefixSet = append(prefixSet, prefix.String())
|
||||
}
|
||||
}
|
||||
|
||||
if len(prefixSet) > 0 {
|
||||
return prefixSet, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("entry %s has no prefix", e.GetName())
|
||||
}
|
||||
|
||||
type IgnoreIPOption func() IPType
|
||||
|
||||
func IgnoreIPv4() IPType {
|
||||
@@ -339,138 +59,3 @@ func IgnoreIPv4() IPType {
|
||||
func IgnoreIPv6() IPType {
|
||||
return IPv6
|
||||
}
|
||||
|
||||
type Container interface {
|
||||
GetEntry(name string) (*Entry, bool)
|
||||
Add(entry *Entry, opts ...IgnoreIPOption) error
|
||||
Remove(name string, opts ...IgnoreIPOption)
|
||||
Loop() <-chan *Entry
|
||||
}
|
||||
|
||||
type container struct {
|
||||
entries *sync.Map // map[name]*Entry
|
||||
}
|
||||
|
||||
func NewContainer() Container {
|
||||
return &container{
|
||||
entries: new(sync.Map),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *container) isValid() bool {
|
||||
if c == nil || c.entries == nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *container) GetEntry(name string) (*Entry, bool) {
|
||||
if !c.isValid() {
|
||||
return nil, false
|
||||
}
|
||||
val, ok := c.entries.Load(strings.ToUpper(strings.TrimSpace(name)))
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return val.(*Entry), true
|
||||
}
|
||||
|
||||
func (c *container) Loop() <-chan *Entry {
|
||||
ch := make(chan *Entry, 300)
|
||||
go func() {
|
||||
c.entries.Range(func(key, value any) bool {
|
||||
ch <- value.(*Entry)
|
||||
return true
|
||||
})
|
||||
close(ch)
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
func (c *container) Add(entry *Entry, opts ...IgnoreIPOption) error {
|
||||
var ignoreIPType IPType
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
ignoreIPType = opt()
|
||||
}
|
||||
}
|
||||
|
||||
name := entry.GetName()
|
||||
val, found := c.GetEntry(name)
|
||||
switch found {
|
||||
case true:
|
||||
var ipv4set, ipv6set *netipx.IPSet
|
||||
var err4, err6 error
|
||||
if entry.hasIPv4Builder() {
|
||||
ipv4set, err4 = entry.ipv4Builder.IPSet()
|
||||
if err4 != nil {
|
||||
return err4
|
||||
}
|
||||
}
|
||||
if entry.hasIPv6Builder() {
|
||||
ipv6set, err6 = entry.ipv6Builder.IPSet()
|
||||
if err6 != nil {
|
||||
return err6
|
||||
}
|
||||
}
|
||||
switch ignoreIPType {
|
||||
case IPv4:
|
||||
if !val.hasIPv6Builder() {
|
||||
val.ipv6Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
val.ipv6Builder.AddSet(ipv6set)
|
||||
case IPv6:
|
||||
if !val.hasIPv4Builder() {
|
||||
val.ipv4Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
val.ipv4Builder.AddSet(ipv4set)
|
||||
default:
|
||||
if !val.hasIPv4Builder() {
|
||||
val.ipv4Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
if !val.hasIPv6Builder() {
|
||||
val.ipv6Builder = new(netipx.IPSetBuilder)
|
||||
}
|
||||
val.ipv4Builder.AddSet(ipv4set)
|
||||
val.ipv6Builder.AddSet(ipv6set)
|
||||
}
|
||||
c.entries.Store(name, val)
|
||||
|
||||
case false:
|
||||
switch ignoreIPType {
|
||||
case IPv4:
|
||||
entry.ipv4Builder = nil
|
||||
case IPv6:
|
||||
entry.ipv6Builder = nil
|
||||
}
|
||||
c.entries.Store(name, entry)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *container) Remove(name string, opts ...IgnoreIPOption) {
|
||||
val, found := c.GetEntry(name)
|
||||
if !found {
|
||||
log.Printf("failed to remove non-existent entry %s", name)
|
||||
return
|
||||
}
|
||||
|
||||
var ignoreIPType IPType
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
ignoreIPType = opt()
|
||||
}
|
||||
}
|
||||
|
||||
switch ignoreIPType {
|
||||
case IPv4:
|
||||
val.ipv6Builder = nil
|
||||
c.entries.Store(name, val)
|
||||
case IPv6:
|
||||
val.ipv4Builder = nil
|
||||
c.entries.Store(name, val)
|
||||
default:
|
||||
c.entries.Delete(name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -113,6 +114,10 @@ func (g *geoLite2CountryCSV) Input(container lib.Container) (lib.Container, erro
|
||||
}
|
||||
}
|
||||
|
||||
if len(entries) == 0 {
|
||||
return nil, fmt.Errorf("❌ [type %s | action %s] no entry is generated", typeCountryCSV, g.Action)
|
||||
}
|
||||
|
||||
var ignoreIPType lib.IgnoreIPOption
|
||||
switch g.OnlyIPType {
|
||||
case lib.IPv4:
|
||||
@@ -121,14 +126,16 @@ func (g *geoLite2CountryCSV) Input(container lib.Container) (lib.Container, erro
|
||||
ignoreIPType = lib.IgnoreIPv4
|
||||
}
|
||||
|
||||
for name, entry := range entries {
|
||||
for _, entry := range entries {
|
||||
switch g.Action {
|
||||
case lib.ActionAdd:
|
||||
if err := container.Add(entry, ignoreIPType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case lib.ActionRemove:
|
||||
container.Remove(name, ignoreIPType)
|
||||
if err := container.Remove(entry, lib.CaseRemovePrefix, ignoreIPType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, lib.ErrUnknownAction
|
||||
}
|
||||
@@ -193,10 +200,8 @@ func (g *geoLite2CountryCSV) process(file string, ccMap map[string]string, entri
|
||||
for _, line := range lines[1:] {
|
||||
ccID := strings.TrimSpace(line[1])
|
||||
if countryCode, found := ccMap[ccID]; found {
|
||||
if len(wantList) > 0 {
|
||||
if _, found := wantList[countryCode]; !found {
|
||||
continue
|
||||
}
|
||||
if len(wantList) > 0 && !wantList[countryCode] {
|
||||
continue
|
||||
}
|
||||
cidrStr := strings.ToLower(strings.TrimSpace(line[0]))
|
||||
entry, found := entries[countryCode]
|
||||
|
||||
@@ -107,7 +107,7 @@ func (g *maxmindMMDBIn) Input(container lib.Container) (lib.Container, error) {
|
||||
}
|
||||
|
||||
if len(entries) == 0 {
|
||||
return nil, fmt.Errorf("❌ [type %s | action %s] no entry is newly generated", typeMaxmindMMDBIn, g.Action)
|
||||
return nil, fmt.Errorf("❌ [type %s | action %s] no entry is generated", typeMaxmindMMDBIn, g.Action)
|
||||
}
|
||||
|
||||
var ignoreIPType lib.IgnoreIPOption
|
||||
@@ -138,7 +138,11 @@ func (g *maxmindMMDBIn) Input(container lib.Container) (lib.Container, error) {
|
||||
return nil, err
|
||||
}
|
||||
case lib.ActionRemove:
|
||||
container.Remove(name, ignoreIPType)
|
||||
if err := container.Remove(entry, lib.CaseRemovePrefix, ignoreIPType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, lib.ErrUnknownAction
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,23 +201,14 @@ func (g *maxmindMMDBIn) generateEntries(entries map[string]*lib.Entry) error {
|
||||
continue
|
||||
}
|
||||
|
||||
var entry *lib.Entry
|
||||
name := strings.ToUpper(record.Country.IsoCode)
|
||||
if theEntry, found := entries[name]; found {
|
||||
entry = theEntry
|
||||
} else {
|
||||
entry, found := entries[name]
|
||||
if !found {
|
||||
entry = lib.NewEntry(name)
|
||||
}
|
||||
|
||||
switch g.Action {
|
||||
case lib.ActionAdd:
|
||||
if err := entry.AddPrefix(subnet); err != nil {
|
||||
return err
|
||||
}
|
||||
case lib.ActionRemove:
|
||||
if err := entry.RemovePrefix(subnet.String()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := entry.AddPrefix(subnet); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entries[name] = entry
|
||||
|
||||
@@ -106,7 +106,7 @@ func (t *textIn) Input(container lib.Container) (lib.Container, error) {
|
||||
}
|
||||
|
||||
if len(entries) == 0 {
|
||||
return nil, fmt.Errorf("type %s | action %s no entry are generated", t.Type, t.Action)
|
||||
return nil, fmt.Errorf("type %s | action %s no entry is generated", t.Type, t.Action)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
@@ -116,7 +116,11 @@ func (t *textIn) Input(container lib.Container) (lib.Container, error) {
|
||||
return nil, err
|
||||
}
|
||||
case lib.ActionRemove:
|
||||
container.Remove(entry.GetName(), ignoreIPType)
|
||||
if err := container.Remove(entry, lib.CaseRemovePrefix, ignoreIPType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, lib.ErrUnknownAction
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ func (s *srsIn) Input(container lib.Container) (lib.Container, error) {
|
||||
}
|
||||
|
||||
if len(entries) == 0 {
|
||||
return nil, fmt.Errorf("type %s | action %s no entry are generated", s.Type, s.Action)
|
||||
return nil, fmt.Errorf("type %s | action %s no entry is generated", s.Type, s.Action)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
@@ -124,7 +124,11 @@ func (s *srsIn) Input(container lib.Container) (lib.Container, error) {
|
||||
return nil, err
|
||||
}
|
||||
case lib.ActionRemove:
|
||||
container.Remove(entry.GetName(), ignoreIPType)
|
||||
if err := container.Remove(entry, lib.CaseRemovePrefix, ignoreIPType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, lib.ErrUnknownAction
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,10 +204,9 @@ func (s *srsIn) walkRemoteFile(url, name string, entries map[string]*lib.Entry)
|
||||
}
|
||||
|
||||
func (s *srsIn) generateEntries(name string, reader io.Reader, entries map[string]*lib.Entry) error {
|
||||
entry := lib.NewEntry(name)
|
||||
if theEntry, found := entries[entry.GetName()]; found {
|
||||
fmt.Printf("⚠️ [type %s | action %s] found duplicated entry: %s. Process anyway\n", typeSRSIn, s.Action, name)
|
||||
entry = theEntry
|
||||
entry, found := entries[name]
|
||||
if !found {
|
||||
entry = lib.NewEntry(name)
|
||||
}
|
||||
|
||||
plainRuleSet, err := srs.Read(reader, true)
|
||||
@@ -213,20 +216,12 @@ func (s *srsIn) generateEntries(name string, reader io.Reader, entries map[strin
|
||||
|
||||
for _, rule := range plainRuleSet.Rules {
|
||||
for _, cidrStr := range rule.DefaultOptions.IPCIDR {
|
||||
switch s.Action {
|
||||
case lib.ActionAdd:
|
||||
if err := entry.AddPrefix(cidrStr); err != nil {
|
||||
return err
|
||||
}
|
||||
case lib.ActionRemove:
|
||||
if err := entry.RemovePrefix(cidrStr); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := entry.AddPrefix(cidrStr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entries[entry.GetName()] = entry
|
||||
|
||||
entries[name] = entry
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -89,7 +89,9 @@ func (c *cutter) Input(container lib.Container) (lib.Container, error) {
|
||||
if len(wantList) > 0 && !wantList[name] {
|
||||
continue
|
||||
}
|
||||
container.Remove(name, ignoreIPType)
|
||||
if err := container.Remove(entry, lib.CaseRemoveEntry, ignoreIPType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return container, nil
|
||||
|
||||
@@ -85,7 +85,9 @@ func (p *private) Input(container lib.Container) (lib.Container, error) {
|
||||
return nil, err
|
||||
}
|
||||
case lib.ActionRemove:
|
||||
container.Remove(entryNamePrivate)
|
||||
if err := container.Remove(entry, lib.CaseRemovePrefix); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, lib.ErrUnknownAction
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package special
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@@ -35,6 +36,10 @@ func newStdin(action lib.Action, data json.RawMessage) (lib.InputConverter, erro
|
||||
}
|
||||
}
|
||||
|
||||
if tmp.Name == "" {
|
||||
return nil, fmt.Errorf("type %s | action %s missing name", typeStdin, action)
|
||||
}
|
||||
|
||||
return &stdin{
|
||||
Type: typeStdin,
|
||||
Action: action,
|
||||
@@ -81,15 +86,8 @@ func (s *stdin) Input(container lib.Container) (lib.Container, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
switch s.Action {
|
||||
case lib.ActionAdd:
|
||||
if err := entry.AddPrefix(line); err != nil {
|
||||
continue
|
||||
}
|
||||
case lib.ActionRemove:
|
||||
if err := entry.RemovePrefix(line); err != nil {
|
||||
continue
|
||||
}
|
||||
if err := entry.AddPrefix(line); err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,8 +103,17 @@ func (s *stdin) Input(container lib.Container) (lib.Container, error) {
|
||||
ignoreIPType = lib.IgnoreIPv4
|
||||
}
|
||||
|
||||
if err := container.Add(entry, ignoreIPType); err != nil {
|
||||
return nil, err
|
||||
switch s.Action {
|
||||
case lib.ActionAdd:
|
||||
if err := container.Add(entry, ignoreIPType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case lib.ActionRemove:
|
||||
if err := container.Remove(entry, lib.CaseRemovePrefix, ignoreIPType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, lib.ErrUnknownAction
|
||||
}
|
||||
|
||||
return container, nil
|
||||
|
||||
@@ -74,31 +74,17 @@ func (s *stdout) Output(container lib.Container) error {
|
||||
}
|
||||
}
|
||||
|
||||
switch len(wantList) {
|
||||
case 0:
|
||||
for entry := range container.Loop() {
|
||||
cidrList, err := s.generateCIDRList(entry)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, cidr := range cidrList {
|
||||
io.WriteString(os.Stdout, cidr+"\n")
|
||||
}
|
||||
for entry := range container.Loop() {
|
||||
if len(wantList) > 0 && !wantList[entry.GetName()] {
|
||||
continue
|
||||
}
|
||||
default:
|
||||
for name := range wantList {
|
||||
entry, found := container.GetEntry(name)
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
cidrList, err := s.generateCIDRList(entry)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, cidr := range cidrList {
|
||||
io.WriteString(os.Stdout, cidr+"\n")
|
||||
}
|
||||
cidrList, err := s.generateCIDRList(entry)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, cidr := range cidrList {
|
||||
io.WriteString(os.Stdout, cidr+"\n")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,9 @@ func (t *test) Input(container lib.Container) (lib.Container, error) {
|
||||
return nil, err
|
||||
}
|
||||
case lib.ActionRemove:
|
||||
container.Remove(entryNameTest)
|
||||
if err := container.Remove(entry, lib.CaseRemovePrefix); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, lib.ErrUnknownAction
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ func (g *geoIPDatIn) Input(container lib.Container) (lib.Container, error) {
|
||||
}
|
||||
|
||||
if len(entries) == 0 {
|
||||
return nil, fmt.Errorf("❌ [type %s | action %s] no entry is newly generated", typeGeoIPdatIn, g.Action)
|
||||
return nil, fmt.Errorf("❌ [type %s | action %s] no entry is generated", typeGeoIPdatIn, g.Action)
|
||||
}
|
||||
|
||||
var ignoreIPType lib.IgnoreIPOption
|
||||
@@ -123,7 +123,11 @@ func (g *geoIPDatIn) Input(container lib.Container) (lib.Container, error) {
|
||||
return nil, err
|
||||
}
|
||||
case lib.ActionRemove:
|
||||
container.Remove(name, ignoreIPType)
|
||||
if err := container.Remove(entry, lib.CaseRemovePrefix, ignoreIPType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, lib.ErrUnknownAction
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,26 +178,16 @@ func (g *geoIPDatIn) generateEntries(reader io.Reader, entries map[string]*lib.E
|
||||
}
|
||||
|
||||
for _, geoip := range geoipList.Entry {
|
||||
var entry *lib.Entry
|
||||
name := geoip.CountryCode
|
||||
if theEntry, found := entries[name]; found {
|
||||
fmt.Printf("⚠️ [type %s | action %s] found duplicated entry: %s. Process anyway\n", typeGeoIPdatIn, g.Action, name)
|
||||
entry = theEntry
|
||||
} else {
|
||||
entry, found := entries[name]
|
||||
if !found {
|
||||
entry = lib.NewEntry(name)
|
||||
}
|
||||
|
||||
for _, v2rayCIDR := range geoip.Cidr {
|
||||
ipStr := net.IP(v2rayCIDR.GetIp()).String() + "/" + fmt.Sprint(v2rayCIDR.GetPrefix())
|
||||
switch g.Action {
|
||||
case lib.ActionAdd:
|
||||
if err := entry.AddPrefix(ipStr); err != nil {
|
||||
return err
|
||||
}
|
||||
case lib.ActionRemove:
|
||||
if err := entry.RemovePrefix(ipStr); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := entry.AddPrefix(ipStr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -155,10 +155,10 @@ func (g *geoIPDatOut) Output(container lib.Container) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Sort to make reproducible builds
|
||||
g.sort(geoIPList)
|
||||
|
||||
if !g.OneFilePerList && updated {
|
||||
// Sort to make reproducible builds
|
||||
g.sort(geoIPList)
|
||||
|
||||
geoIPBytes, err := proto.Marshal(geoIPList)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -305,10 +305,10 @@ generate_static_system() {
|
||||
set system.ntp='timeserver'
|
||||
set system.ntp.enabled='1'
|
||||
set system.ntp.enable_server='1'
|
||||
add_list system.ntp.server='ntp.aliyun.com'
|
||||
add_list system.ntp.server='time1.cloud.tencent.com'
|
||||
add_list system.ntp.server='time.ustc.edu.cn'
|
||||
add_list system.ntp.server='cn.pool.ntp.org'
|
||||
add_list system.ntp.server='time.apple.com'
|
||||
add_list system.ntp.server='time.google.com'
|
||||
add_list system.ntp.server='time.windows.com'
|
||||
add_list system.ntp.server='time.cloudflare.com'
|
||||
EOF
|
||||
|
||||
if json_is_a system object; then
|
||||
|
||||
@@ -3,8 +3,16 @@
|
||||
uci set luci.main.lang=zh_cn
|
||||
uci commit luci
|
||||
|
||||
uci set system.@system[0].timezone=CST-8
|
||||
uci set system.@system[0].zonename=Asia/Shanghai
|
||||
uci -q batch <<-EOF
|
||||
set system.@system[0].timezone='CST-8'
|
||||
set system.@system[0].zonename='Asia/Shanghai'
|
||||
|
||||
delete system.ntp.server
|
||||
add_list system.ntp.server='ntp1.aliyun.com'
|
||||
add_list system.ntp.server='ntp.tencent.com'
|
||||
add_list system.ntp.server='ntp.ntsc.ac.cn'
|
||||
add_list system.ntp.server='time.ustc.edu.cn'
|
||||
EOF
|
||||
uci commit system
|
||||
|
||||
uci set fstab.@global[0].anon_mount=1
|
||||
@@ -28,9 +36,7 @@ sed -i 's/\"services\"/\"nas\"/g' /usr/lib/lua/luci/controller/usb_printer.lua
|
||||
sed -i 's/\"services\"/\"nas\"/g' /usr/lib/lua/luci/controller/xunlei.lua
|
||||
sed -i 's/services/nas/g' /usr/lib/lua/luci/view/minidlna_status.htm
|
||||
|
||||
#ln -sf /sbin/ip /usr/bin/ip
|
||||
|
||||
sed -i 's#downloads.openwrt.org#mirrors.cloud.tencent.com/lede#g' /etc/opkg/distfeeds.conf
|
||||
sed -i 's#downloads.openwrt.org#mirrors.tencent.com/lede#g' /etc/opkg/distfeeds.conf
|
||||
sed -i 's/root::0:0:99999:7:::/root:$1$V4UetPzk$CYXluq4wUazHjmCDBCqXF.:0:0:99999:7:::/g' /etc/shadow
|
||||
sed -i 's/root:::0:99999:7:::/root:$1$V4UetPzk$CYXluq4wUazHjmCDBCqXF.:0:0:99999:7:::/g' /etc/shadow
|
||||
|
||||
@@ -40,12 +46,6 @@ sed -i '/openwrt_luci/ { s/snapshots/releases\/18.06.9/g; }' /etc/opkg/distfeed
|
||||
sed -i '/check_signature/d' /etc/opkg.conf
|
||||
|
||||
sed -i '/REDIRECT --to-ports 53/d' /etc/firewall.user
|
||||
#echo 'iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 53' >> /etc/firewall.user
|
||||
#echo 'iptables -t nat -A PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports 53' >> /etc/firewall.user
|
||||
#echo '[ -n "$(command -v ip6tables)" ] && ip6tables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 53' >> /etc/firewall.user
|
||||
#echo '[ -n "$(command -v ip6tables)" ] && ip6tables -t nat -A PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports 53' >> /etc/firewall.user
|
||||
|
||||
#echo 'iptables -A OUTPUT -m string --string "api.installer.xiaomi.cn" --algo bm --to 65535 -j DROP' >> /etc/firewall.user
|
||||
|
||||
sed -i '/option disabled/d' /etc/config/wireless
|
||||
sed -i '/set wireless.radio${devidx}.disabled/d' /lib/wifi/mac80211.sh
|
||||
@@ -58,11 +58,7 @@ echo "DISTRIB_DESCRIPTION='OpenWrt '" >> /etc/openwrt_release
|
||||
sed -i '/log-facility/d' /etc/dnsmasq.conf
|
||||
echo "log-facility=/dev/null" >> /etc/dnsmasq.conf
|
||||
|
||||
if [ -f /www/luci-static/resources/luci.js ]; then
|
||||
sed -i 's/ifname/device/g' /etc/config/network
|
||||
else
|
||||
sed -i 's/device/ifname/g' /etc/config/network
|
||||
fi
|
||||
#ln -sf /sbin/ip /usr/bin/ip
|
||||
|
||||
rm -rf /tmp/luci-modulecache/
|
||||
rm -f /tmp/luci-indexcache
|
||||
|
||||
@@ -184,25 +184,25 @@
|
||||
&dp1 {
|
||||
status = "okay";
|
||||
phy-handle = <&qca8075_0>;
|
||||
label = "wan";
|
||||
label = "lan1";
|
||||
};
|
||||
|
||||
&dp2 {
|
||||
status = "okay";
|
||||
phy-handle = <&qca8075_1>;
|
||||
label = "lan1";
|
||||
label = "lan2";
|
||||
};
|
||||
|
||||
&dp3 {
|
||||
status = "okay";
|
||||
phy-handle = <&qca8075_2>;
|
||||
label = "lan2";
|
||||
label = "lan3";
|
||||
};
|
||||
|
||||
&dp4 {
|
||||
status = "okay";
|
||||
phy-handle = <&qca8075_3>;
|
||||
label = "lan3";
|
||||
label = "wan";
|
||||
};
|
||||
|
||||
&wifi {
|
||||
|
||||
@@ -271,6 +271,5 @@
|
||||
|
||||
&wifi {
|
||||
status = "okay";
|
||||
qcom,ath11k-calibration-variant = "JDC-AX1800-Pro";
|
||||
qcom,ath11k-fw-memory-mode = <1>;
|
||||
qcom,ath11k-calibration-variant = "JDC-AX6600";
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ PKG_RELEASE:=1
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/AdguardTeam/AdGuardHome/tar.gz/v$(PKG_VERSION)?
|
||||
PKG_HASH:=de6d99c4420d131b76e5d22b58ac91159e74e5783f02ada8b2f993f353e254f9
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/AdGuardHome-$(PKG_VERSION)
|
||||
|
||||
PKG_LICENSE:=GPL-3.0-only
|
||||
PKG_LICENSE_FILES:=LICENSE.txt
|
||||
@@ -57,17 +58,13 @@ define Download/adguardhome-frontend
|
||||
URL:=https://github.com/AdguardTeam/AdGuardHome/releases/download/v$(PKG_VERSION)/
|
||||
URL_FILE:=AdGuardHome_frontend.tar.gz
|
||||
FILE:=$(FRONTEND_FILE)
|
||||
HASH:=af9ae57b55a09a0aaf7c9a69a46734827443f98135d4c4b176874de3f9a449d8
|
||||
HASH:=af9ae57b55a09a0aaf7c9a69a46734827443f98135d4c4b176874de3f9a449d8
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
$(call Build/Prepare/Default)
|
||||
if [ -d "$(BUILD_DIR)/AdGuardHome-$(PKG_VERSION)" ]; then \
|
||||
mv "$(BUILD_DIR)/AdGuardHome-$(PKG_VERSION)/"* "$(BUILD_DIR)/adguardhome-$(PKG_VERSION)/"; \
|
||||
fi
|
||||
|
||||
gzip -dc $(DL_DIR)/$(FRONTEND_FILE) | $(HOST_TAR) -C $(PKG_BUILD_DIR)/ $(TAR_OPTIONS)
|
||||
( cd "$(BUILD_DIR)/adguardhome-$(PKG_VERSION)"; go mod tidy )
|
||||
endef
|
||||
|
||||
define Package/adguardhome/install
|
||||
|
||||
@@ -1111,7 +1111,7 @@ add_firewall_rule() {
|
||||
$ip6t_m -I OUTPUT $(comment "mangle-OUTPUT-PSW") -o lo -j RETURN
|
||||
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW) -m mark --mark 1 -j RETURN"
|
||||
|
||||
[ $(config_t_get global dns_redirect) == "1" ] && {
|
||||
[ $(config_t_get global dns_redirect "0") = "1" ] && {
|
||||
$ipt_m -A PSW -p udp --dport 53 -j RETURN
|
||||
$ip6t_m -A PSW -p udp --dport 53 -j RETURN
|
||||
$ipt_n -I PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 53 -m comment --comment "PSW_DNS_Hijack" 2>/dev/null
|
||||
|
||||
@@ -1152,7 +1152,7 @@ add_firewall_rule() {
|
||||
nft "add rule inet fw4 mangle_output oif lo counter return comment \"PSW_OUTPUT_MANGLE\""
|
||||
nft "add rule inet fw4 mangle_output meta mark 1 counter return comment \"PSW_OUTPUT_MANGLE\""
|
||||
|
||||
[ $(config_t_get global dns_redirect) == "1" ] && {
|
||||
[ $(config_t_get global dns_redirect "0") = "1" ] && {
|
||||
nft "add rule inet fw4 PSW_MANGLE ip protocol udp udp dport 53 counter return"
|
||||
nft "add rule inet fw4 PSW_MANGLE_V6 meta l4proto udp udp dport 53 counter return"
|
||||
nft insert rule inet fw4 dstnat position 0 tcp dport 53 counter redirect to :53 comment \"PSW_DNS_Hijack\" 2>/dev/null
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! AEAD packet I/O facilities
|
||||
//!
|
||||
//! AEAD protocol is defined in <https://shadowsocks.org/en/spec/AEAD.html>.
|
||||
//! AEAD protocol is defined in <https://shadowsocks.org/doc/aead.html>.
|
||||
//!
|
||||
//! ```plain
|
||||
//! TCP request (before encryption)
|
||||
@@ -305,7 +305,7 @@ impl DecryptedReader {
|
||||
};
|
||||
|
||||
if plen > MAX_PACKET_SIZE {
|
||||
// https://shadowsocks.org/en/spec/AEAD-Ciphers.html
|
||||
// https://shadowsocks.org/doc/aead.html
|
||||
//
|
||||
// AEAD TCP protocol have reserved the higher two bits for future use
|
||||
return Err(ProtocolError::DataTooLong(plen));
|
||||
|
||||
@@ -181,7 +181,7 @@ pub fn define_command_line_options(mut app: Command) -> Command {
|
||||
.action(ArgAction::Set)
|
||||
.value_hint(ValueHint::CommandName)
|
||||
.requires("SERVER_ADDR")
|
||||
.help("SIP003 (https://shadowsocks.org/guide/sip003.html) plugin"),
|
||||
.help("SIP003 (https://shadowsocks.org/doc/sip003.html) plugin"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("PLUGIN_MODE")
|
||||
@@ -206,7 +206,7 @@ pub fn define_command_line_options(mut app: Command) -> Command {
|
||||
.action(ArgAction::Set)
|
||||
.value_hint(ValueHint::Url)
|
||||
.value_parser(vparser::parse_server_url)
|
||||
.help("Server address in SIP002 (https://shadowsocks.org/guide/sip002.html) URL"),
|
||||
.help("Server address in SIP002 (https://shadowsocks.org/doc/sip002.html) URL"),
|
||||
)
|
||||
.group(ArgGroup::new("SERVER_CONFIG")
|
||||
.arg("SERVER_ADDR").arg("SERVER_URL").multiple(true))
|
||||
|
||||
@@ -93,7 +93,7 @@ pub fn define_command_line_options(mut app: Command) -> Command {
|
||||
.num_args(1)
|
||||
.action(ArgAction::Set)
|
||||
.value_hint(ValueHint::CommandName)
|
||||
.help("Default SIP003 (https://shadowsocks.org/guide/sip003.html) plugin"),
|
||||
.help("Default SIP003 (https://shadowsocks.org/doc/sip003.html) plugin"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("PLUGIN_MODE")
|
||||
|
||||
@@ -121,7 +121,7 @@ pub fn define_command_line_options(mut app: Command) -> Command {
|
||||
.action(ArgAction::Set)
|
||||
.value_hint(ValueHint::CommandName)
|
||||
.requires("SERVER_ADDR")
|
||||
.help("SIP003 (https://shadowsocks.org/guide/sip003.html) plugin"),
|
||||
.help("SIP003 (https://shadowsocks.org/doc/sip003.html) plugin"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("PLUGIN_MODE")
|
||||
@@ -494,7 +494,7 @@ pub fn create(matches: &ArgMatches) -> Result<(Runtime, impl Future<Output = Exi
|
||||
eprintln!(
|
||||
"missing proxy servers, consider specifying it by \
|
||||
--server-addr, --encrypt-method, --password command line option, \
|
||||
or configuration file, check more details in https://shadowsocks.org/guide/configs.html"
|
||||
or configuration file, check more details in https://shadowsocks.org/doc/configs.html"
|
||||
);
|
||||
return Err(crate::EXIT_CODE_INSUFFICIENT_PARAMS.into());
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ value_parser_type!(parse_cipher_kind, CipherKind, "invalid cipher");
|
||||
pub fn parse_server_url(v: &str) -> Result<ServerConfig, String> {
|
||||
match ServerConfig::from_url(v) {
|
||||
Ok(t) => Ok(t),
|
||||
Err(..) => Err("should be SIP002 (https://shadowsocks.org/guide/sip002.html) format".to_owned()),
|
||||
Err(..) => Err("should be SIP002 (https://shadowsocks.org/doc/sip002.html) format".to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1111,7 +1111,7 @@ add_firewall_rule() {
|
||||
$ip6t_m -I OUTPUT $(comment "mangle-OUTPUT-PSW") -o lo -j RETURN
|
||||
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW) -m mark --mark 1 -j RETURN"
|
||||
|
||||
[ $(config_t_get global dns_redirect) == "1" ] && {
|
||||
[ $(config_t_get global dns_redirect "0") = "1" ] && {
|
||||
$ipt_m -A PSW -p udp --dport 53 -j RETURN
|
||||
$ip6t_m -A PSW -p udp --dport 53 -j RETURN
|
||||
$ipt_n -I PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 53 -m comment --comment "PSW_DNS_Hijack" 2>/dev/null
|
||||
|
||||
@@ -1152,7 +1152,7 @@ add_firewall_rule() {
|
||||
nft "add rule inet fw4 mangle_output oif lo counter return comment \"PSW_OUTPUT_MANGLE\""
|
||||
nft "add rule inet fw4 mangle_output meta mark 1 counter return comment \"PSW_OUTPUT_MANGLE\""
|
||||
|
||||
[ $(config_t_get global dns_redirect) == "1" ] && {
|
||||
[ $(config_t_get global dns_redirect "0") = "1" ] && {
|
||||
nft "add rule inet fw4 PSW_MANGLE ip protocol udp udp dport 53 counter return"
|
||||
nft "add rule inet fw4 PSW_MANGLE_V6 meta l4proto udp udp dport 53 counter return"
|
||||
nft insert rule inet fw4 dstnat position 0 tcp dport 53 counter redirect to :53 comment \"PSW_DNS_Hijack\" 2>/dev/null
|
||||
|
||||
@@ -35,8 +35,6 @@ do
|
||||
echo "appdmg V2rayU-64.dmg"
|
||||
rm -f V2rayU-64.dmg
|
||||
appdmg appdmg.json "V2rayU-64.dmg"
|
||||
#rm -fr release/V2rayU.app
|
||||
./sign_update "V2rayU-64.dmg"
|
||||
|
||||
break
|
||||
;;
|
||||
@@ -48,8 +46,6 @@ do
|
||||
echo "appdmg V2rayU-arm64.dmg"
|
||||
rm -f V2rayU-arm64.dmg
|
||||
appdmg appdmg.json "V2rayU-arm64.dmg"
|
||||
#rm -fr release/V2rayU.app
|
||||
./sign_update "V2rayU-64.dmg"
|
||||
|
||||
break
|
||||
;;
|
||||
|
||||
+10
-10
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>compileBitcode</key>
|
||||
<false/>
|
||||
<key>method</key>
|
||||
<string>development</string>
|
||||
</dict>
|
||||
</plist>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>method</key>
|
||||
<dict/>
|
||||
<key>development</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# publish.sh
|
||||
# V2rayU
|
||||
#
|
||||
# Created by yanue on 2019/7/18.
|
||||
# Copyright © 2019 yanue. All rights reserved.
|
||||
|
||||
read -p "请输入版本描述: " release_note
|
||||
#pushRelease ${release_note}
|
||||
generateAppcast ${release_note}
|
||||
|
||||
echo "Done"
|
||||
+38
-7
@@ -13,26 +13,60 @@ APP_TITLE="${APP_NAME} - V${APP_Version}"
|
||||
AppCastDir=$HOME/swift/appcast
|
||||
|
||||
function updatePlistVersion() {
|
||||
echo "Updating plist version..."
|
||||
buildString=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${BASE_DIR}/V2rayU/${INFOPLIST_FILE}")
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildString" "${BASE_DIR}/V2rayU/${INFOPLIST_FILE}"
|
||||
if [ $? -eq 0 ]; then
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildString" "${BASE_DIR}/V2rayU/${INFOPLIST_FILE}"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to set CFBundleVersion"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Error: Failed to read CFBundleShortVersionString"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function build() {
|
||||
echo "Building V2rayU."${APP_Version}
|
||||
echo "Building V2rayU version ${APP_Version}"
|
||||
|
||||
echo "Cleaning up old archive & app..."
|
||||
rm -rf ${V2rayU_ARCHIVE} ${V2rayU_RELEASE}
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to clean up old archive & app"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Building archive... please wait a minute"
|
||||
xcodebuild -workspace ${BASE_DIR}/V2rayU.xcworkspace -config Release -scheme V2rayU -archivePath ${V2rayU_ARCHIVE} archive
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to build archive"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Exporting archive..."
|
||||
xcodebuild -archivePath ${V2rayU_ARCHIVE} -exportArchive -exportPath ${V2rayU_RELEASE} -exportOptionsPlist ./build.plist
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to export archive"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Cleaning up archive..."
|
||||
rm -rf ${V2rayU_ARCHIVE}
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to clean up archive"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Setting permissions for resources..."
|
||||
chmod -R 755 "${V2rayU_RELEASE}/${APP_NAME}.app/Contents/Resources/v2ray-core"
|
||||
chmod -R 755 "${V2rayU_RELEASE}/${APP_NAME}.app/Contents/Resources/unzip.sh"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to set permissions for resources"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Build and export completed successfully."
|
||||
}
|
||||
|
||||
function createDmg() {
|
||||
@@ -209,9 +243,6 @@ function createDmgByAppdmg() {
|
||||
echo ${BUILD_DIR}/appdmg.json
|
||||
appdmg appdmg.json ${DMG_FINAL}
|
||||
|
||||
# appcast sign update
|
||||
${AppCastDir}/bin/sign_update ${DMG_FINAL}
|
||||
|
||||
# umount "/Volumes/${APP_NAME}"
|
||||
}
|
||||
|
||||
@@ -256,7 +287,7 @@ function makeDmg() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#makeDmg
|
||||
createDmgByAppdmg
|
||||
|
||||
echo 'done'
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# sign.sh
|
||||
# V2rayU
|
||||
#
|
||||
# Created by yanue on 2023/8/1.
|
||||
# Copyright © 2023 yanue. All rights reserved.
|
||||
set -ex
|
||||
|
||||
TOKEN=$1
|
||||
release_id=$2
|
||||
|
||||
echo "token $TOKEN, release ${RELEASE_ID}"
|
||||
|
||||
curl -X "PATCH" "https://api.appcenter.ms/v0.1/apps/yanue/V2rayU/releases/${release_id}" \
|
||||
-H "X-API-Token: $TOKEN" \
|
||||
-H 'Content-Type: application/json; charset=utf-8' \
|
||||
-d '{
|
||||
"release_notes": "test",
|
||||
"metadata": {
|
||||
"ed_signature": "PW8pDnr5VZkmC93gZjUDlHI8gkJSspPoDU3DdhsMkps"
|
||||
}
|
||||
}'
|
||||
Binary file not shown.
+3
-4
@@ -10,8 +10,7 @@ target 'V2rayU' do
|
||||
# Pods for V2rayU
|
||||
pod 'FirebaseAnalytics', '~> 10.24.0'
|
||||
pod 'FirebaseCrashlytics'
|
||||
pod 'Alamofire'
|
||||
pod 'SwiftyJSON'
|
||||
pod 'SwiftyJSON'/
|
||||
# master branch
|
||||
pod 'Preferences', :git => 'https://github.com/sindresorhus/Preferences.git'
|
||||
pod 'QRCoder'
|
||||
@@ -21,11 +20,11 @@ target 'V2rayU' do
|
||||
|
||||
end
|
||||
|
||||
# fix libarclite_macosx.a need min deploy target 10.14
|
||||
# fix libarclite_macosx.a need min deploy target 11.0
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['MACOSX_DEPLOYMENT_TARGET'] = '10.14'
|
||||
config.build_settings['MACOSX_DEPLOYMENT_TARGET'] = '11.0'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+1
-9
@@ -1,5 +1,4 @@
|
||||
PODS:
|
||||
- Alamofire (4.8.2)
|
||||
- FirebaseAnalytics (10.24.0):
|
||||
- FirebaseAnalytics/AdIdSupport (= 10.24.0)
|
||||
- FirebaseCore (~> 10.0)
|
||||
@@ -112,26 +111,22 @@ PODS:
|
||||
- PromisesSwift (2.4.0):
|
||||
- PromisesObjC (= 2.4.0)
|
||||
- QRCoder (1.1.0)
|
||||
- Sparkle (2.6.2)
|
||||
- Swifter (1.4.7)
|
||||
- SwiftyJSON (5.0.0)
|
||||
- Yams (5.0.6)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Alamofire
|
||||
- FirebaseAnalytics (~> 10.24.0)
|
||||
- FirebaseCrashlytics
|
||||
- MASShortcut
|
||||
- Preferences (from `https://github.com/sindresorhus/Preferences.git`)
|
||||
- QRCoder
|
||||
- Sparkle (~> 2.0)
|
||||
- Swifter
|
||||
- SwiftyJSON
|
||||
- Yams
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/CocoaPods/Specs.git:
|
||||
- Alamofire
|
||||
- FirebaseAnalytics
|
||||
- FirebaseCore
|
||||
- FirebaseCoreExtension
|
||||
@@ -148,7 +143,6 @@ SPEC REPOS:
|
||||
- PromisesObjC
|
||||
- PromisesSwift
|
||||
- QRCoder
|
||||
- Sparkle
|
||||
- Swifter
|
||||
- SwiftyJSON
|
||||
- Yams
|
||||
@@ -163,7 +157,6 @@ CHECKOUT OPTIONS:
|
||||
:git: https://github.com/sindresorhus/Preferences.git
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: ae5c501addb7afdbb13687d7f2f722c78734c2d3
|
||||
FirebaseAnalytics: b5efc493eb0f40ec560b04a472e3e1a15d39ca13
|
||||
FirebaseCore: 11dc8a16dfb7c5e3c3f45ba0e191a33ac4f50894
|
||||
FirebaseCoreExtension: af5fd85e817ea9d19f9a2659a376cf9cf99f03c0
|
||||
@@ -181,11 +174,10 @@ SPEC CHECKSUMS:
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
|
||||
QRCoder: cbd2bee531cc86d286df7942334cfed94c803ae4
|
||||
Sparkle: a62c7dc4f410ced73beb2169cf1d3cc3f028a295
|
||||
Swifter: 2327ef5d872c638aebab79646ce494af508b0c8f
|
||||
SwiftyJSON: 36413e04c44ee145039d332b4f4e2d3e8d6c4db7
|
||||
Yams: e10dae147f517ed57ecae37c5e8681bdf8fcab65
|
||||
|
||||
PODFILE CHECKSUM: 071aabe40b11d56fb50a9b83f6ed47079838bdee
|
||||
PODFILE CHECKSUM: d61ad825ad5d61b2b98237544e21946c9babe3a0
|
||||
|
||||
COCOAPODS: 1.15.2
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
664EB377216C9A5F00B6AE0D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 664EB376216C9A5F00B6AE0D /* Assets.xcassets */; };
|
||||
664EB392216CA9E800B6AE0D /* ConfigWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 664EB390216CA9E800B6AE0D /* ConfigWindow.swift */; };
|
||||
6662C20B240EA782000AF6CD /* PreferenceDns.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6662C209240EA782000AF6CD /* PreferenceDns.xib */; };
|
||||
667029CA21AF8E7A0079EF41 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 667029C921AF8E7A0079EF41 /* Sparkle.framework */; };
|
||||
667029D321AFB86E0079EF41 /* QrcodeWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 667029D121AFB86E0079EF41 /* QrcodeWindow.xib */; };
|
||||
66784AFC2170486D00AD307F /* Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66784AFB2170486D00AD307F /* Util.swift */; };
|
||||
667ECE722A9A05EC009B00EC /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 667ECE712A9A05EC009B00EC /* main.swift */; };
|
||||
@@ -110,15 +109,11 @@
|
||||
6608D9DD2182C92D00A0E0DD /* v2rayOutbound.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = v2rayOutbound.swift; sourceTree = "<group>"; };
|
||||
6608D9E12182C9C100A0E0DD /* v2rayStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = v2rayStream.swift; sourceTree = "<group>"; };
|
||||
660D0E59216E0158000C2922 /* V2rayServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = V2rayServer.swift; sourceTree = "<group>"; usesTabs = 0; wrapsLines = 0; };
|
||||
66107B8722DEDBE4002FFB60 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
66107B8922DEE445002FFB60 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
6618372823E9BF1A000F7410 /* ToastWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToastWindow.swift; sourceTree = "<group>"; };
|
||||
6618372D23E9BF73000F7410 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ToastWindow.xib; sourceTree = "<group>"; };
|
||||
66193A8523EE45B200289B6A /* PreferenceRouting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferenceRouting.swift; sourceTree = "<group>"; };
|
||||
66193A8823EE46BC00289B6A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = V2rayU/Base.lproj/PreferenceRouting.xib; sourceTree = SOURCE_ROOT; };
|
||||
66193A9323EF1EF600289B6A /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "../zh-Hans.lproj/PreferenceRouting.strings"; sourceTree = "<group>"; };
|
||||
66193A9523EF1EFA00289B6A /* zh-HK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-HK"; path = "../zh-HK.lproj/PreferenceRouting.strings"; sourceTree = "<group>"; };
|
||||
6625848D2AB745E700DFDC1E /* sign.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = sign.sh; sourceTree = "<group>"; };
|
||||
6625848E2AB746D500DFDC1E /* appdmg.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = appdmg.sh; sourceTree = "<group>"; };
|
||||
662F0ACE2AB720C700884C17 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = ../en.lproj/PreferenceGeneral.strings; sourceTree = "<group>"; };
|
||||
663F040525ED4B2C00687600 /* V2rayLaunch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = V2rayLaunch.swift; sourceTree = "<group>"; };
|
||||
@@ -126,19 +121,17 @@
|
||||
664B95DD217062A500DBC941 /* Alamofire */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Alamofire; path = Pods/Alamofire; sourceTree = "<group>"; };
|
||||
664BAC462C2DB0E100654FB7 /* V2rayRouting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = V2rayRouting.swift; sourceTree = "<group>"; };
|
||||
664BAC482C314CD600654FB7 /* AppVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersion.swift; sourceTree = "<group>"; };
|
||||
664BAC4F2C394AA000654FB7 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "../zh-Hans.lproj/PreferenceRouting.strings"; sourceTree = "<group>"; };
|
||||
664EB371216C9A5E00B6AE0D /* V2rayU.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = V2rayU.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
664EB374216C9A5E00B6AE0D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
664EB376216C9A5F00B6AE0D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
664EB379216C9A5F00B6AE0D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||
664EB37B216C9A5F00B6AE0D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
664EB390216CA9E800B6AE0D /* ConfigWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigWindow.swift; sourceTree = "<group>"; };
|
||||
664FC05321A70C4300048FE3 /* build.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = build.plist; sourceTree = "<group>"; };
|
||||
6653C20422E0A2B700754D66 /* publish.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = publish.sh; sourceTree = "<group>"; };
|
||||
665DC9BA22A542F90062337B /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
|
||||
6662C20A240EA782000AF6CD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = V2rayU/Base.lproj/PreferenceDns.xib; sourceTree = SOURCE_ROOT; };
|
||||
6662C20C240EA794000AF6CD /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "../zh-Hans.lproj/PreferenceDns.strings"; sourceTree = "<group>"; };
|
||||
6662C20D240EA797000AF6CD /* zh-HK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-HK"; path = "../zh-HK.lproj/PreferenceDns.strings"; sourceTree = "<group>"; };
|
||||
667029C921AF8E7A0079EF41 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = "../../Downloads/Sparkle-1.21.0/Sparkle.framework"; sourceTree = "<group>"; };
|
||||
667029D221AFB86E0079EF41 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/QrcodeWindow.xib; sourceTree = "<group>"; };
|
||||
66784AFB2170486D00AD307F /* Util.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Util.swift; sourceTree = "<group>"; };
|
||||
667ECE6F2A9A05EB009B00EC /* V2rayUTool */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = V2rayUTool; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -154,7 +147,9 @@
|
||||
669A73AC233776B900807CF9 /* zh-HK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-HK"; path = "../zh-HK.lproj/PreferenceGeneral.strings"; sourceTree = "<group>"; };
|
||||
669A73AD233776B900807CF9 /* zh-HK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-HK"; path = "../zh-HK.lproj/PreferencePac.strings"; sourceTree = "<group>"; };
|
||||
669A73AE233776B900807CF9 /* zh-HK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-HK"; path = "../zh-HK.lproj/PreferenceSubscription.strings"; sourceTree = "<group>"; };
|
||||
669A73AF233776B900807CF9 /* zh-HK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-HK"; path = "zh-HK.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
66A358662C39517B00914A25 /* zh-HK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-HK"; path = "zh-HK.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
66A358672C39517F00914A25 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
66A358682C3959AE00914A25 /* build.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = build.plist; sourceTree = "<group>"; };
|
||||
66A5CE4521706B5A009B08B2 /* Pods_V2rayU.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Pods_V2rayU.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
66A77BE2268225790097A126 /* v2ray-core */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "v2ray-core"; path = "Build/v2ray-core"; sourceTree = "<group>"; };
|
||||
66ACB19F21757D5B005B5881 /* MainMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainMenu.swift; sourceTree = "<group>"; };
|
||||
@@ -205,7 +200,6 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
667029CA21AF8E7A0079EF41 /* Sparkle.framework in Frameworks */,
|
||||
66973EB721797719001FEA1E /* ServiceManagement.framework in Frameworks */,
|
||||
F260898E336CFA5EAB07ADC9 /* Pods_V2rayU.framework in Frameworks */,
|
||||
);
|
||||
@@ -313,12 +307,10 @@
|
||||
66FEAD44217D75D7009DECF9 /* Build */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
66A358682C3959AE00914A25 /* build.plist */,
|
||||
6625848E2AB746D500DFDC1E /* appdmg.sh */,
|
||||
6625848D2AB745E700DFDC1E /* sign.sh */,
|
||||
664FC05321A70C4300048FE3 /* build.plist */,
|
||||
66FEAD45217D75FC009DECF9 /* release.sh */,
|
||||
6D6DFD93CE866018306A090E /* pac */,
|
||||
6653C20422E0A2B700754D66 /* publish.sh */,
|
||||
6D6DF927AC79EEF7378C192A /* appdmg.json */,
|
||||
);
|
||||
path = Build;
|
||||
@@ -360,7 +352,6 @@
|
||||
children = (
|
||||
665DC9BA22A542F90062337B /* AppKit.framework */,
|
||||
664666A021CBD6C60094F0B7 /* libPods-V2rayUTool.a */,
|
||||
667029C921AF8E7A0079EF41 /* Sparkle.framework */,
|
||||
66973EB621797719001FEA1E /* ServiceManagement.framework */,
|
||||
66A5CE4521706B5A009B08B2 /* Pods_V2rayU.framework */,
|
||||
664B95DD217062A500DBC941 /* Alamofire */,
|
||||
@@ -595,9 +586,9 @@
|
||||
66107B8822DEDBE4002FFB60 /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
66107B8722DEDBE4002FFB60 /* zh-Hans */,
|
||||
66107B8922DEE445002FFB60 /* en */,
|
||||
669A73AF233776B900807CF9 /* zh-HK */,
|
||||
66A358662C39517B00914A25 /* zh-HK */,
|
||||
66A358672C39517F00914A25 /* zh-Hans */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
@@ -614,8 +605,7 @@
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
66193A8823EE46BC00289B6A /* Base */,
|
||||
66193A9323EF1EF600289B6A /* zh-Hans */,
|
||||
66193A9523EF1EFA00289B6A /* zh-HK */,
|
||||
664BAC4F2C394AA000654FB7 /* zh-Hans */,
|
||||
);
|
||||
name = PreferenceRouting.xib;
|
||||
sourceTree = "<group>";
|
||||
@@ -844,14 +834,15 @@
|
||||
buildSettings = {
|
||||
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 4.0.0;
|
||||
CURRENT_PROJECT_VERSION = 4.2.0;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = RJYEH6TCJD;
|
||||
ENABLE_ONLY_ACTIVE_RESOURCES = YES;
|
||||
INFOPLIST_FILE = V2rayU/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = V2rayU;
|
||||
@@ -860,7 +851,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MARKETING_VERSION = 4.0.0;
|
||||
MARKETING_VERSION = 4.2.0;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.yanue.V2rayU;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -878,14 +869,15 @@
|
||||
buildSettings = {
|
||||
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 4.0.0;
|
||||
CURRENT_PROJECT_VERSION = 4.2.0;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = RJYEH6TCJD;
|
||||
ENABLE_ONLY_ACTIVE_RESOURCES = YES;
|
||||
INFOPLIST_FILE = V2rayU/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = V2rayU;
|
||||
@@ -894,7 +886,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MARKETING_VERSION = 4.0.0;
|
||||
MARKETING_VERSION = 4.2.0;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.yanue.V2rayU;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -912,8 +904,9 @@
|
||||
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = RJYEH6TCJD;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -927,8 +920,9 @@
|
||||
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = RJYEH6TCJD;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
||||
+105
-48
@@ -45,6 +45,16 @@ struct GithubAsset: Codable {
|
||||
}
|
||||
}
|
||||
|
||||
struct GithubError: Codable {
|
||||
let message: String
|
||||
let documentationUrl: String
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case message
|
||||
case documentationUrl = "documentation_url"
|
||||
}
|
||||
}
|
||||
|
||||
let V2rayUpdater = AppCheckController()
|
||||
|
||||
// AppCheckController - 检查新版本页面
|
||||
@@ -169,22 +179,46 @@ class AppCheckController: NSWindowController {
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
print("Error decoding JSON: \(error)")
|
||||
DispatchQueue.main.async {
|
||||
// update progress text
|
||||
self.bindData.progressText = "Check failed: \(error)"
|
||||
var title = "Check failed!"
|
||||
var toast = "\(error)"
|
||||
if isMainland {
|
||||
title = "检查失败"
|
||||
toast = "\(error)";
|
||||
// 可能请求太频繁了
|
||||
do {
|
||||
let decoder = JSONDecoder()
|
||||
|
||||
// try decode data
|
||||
let data: GithubError = try decoder.decode(GithubError.self, from: data)
|
||||
DispatchQueue.main.async {
|
||||
// update progress text
|
||||
self.bindData.progressText = "Check failed: \(error)"
|
||||
var title = "Check failed!"
|
||||
if isMainland {
|
||||
title = "检查失败"
|
||||
}
|
||||
var toast = "\(data.message)\n\(data.documentationUrl)";
|
||||
// open dialog
|
||||
alertDialog(title: title, message: toast)
|
||||
// sleep 2s
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
// close window
|
||||
self.closeWindow()
|
||||
}
|
||||
}
|
||||
// open dialog
|
||||
alertDialog(title: title, message: toast)
|
||||
// sleep 2s
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
// close window
|
||||
self.closeWindow()
|
||||
} catch {
|
||||
print("Error decoding JSON: \(error)")
|
||||
DispatchQueue.main.async {
|
||||
// update progress text
|
||||
self.bindData.progressText = "Check failed: \(error)"
|
||||
var title = "Check failed!"
|
||||
var toast = "\(error)"
|
||||
if isMainland {
|
||||
title = "检查失败"
|
||||
toast = "\(error)";
|
||||
}
|
||||
// open dialog
|
||||
alertDialog(title: title, message: toast)
|
||||
// sleep 2s
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
// close window
|
||||
self.closeWindow()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,7 +292,7 @@ class AppVersionController: NSWindowController {
|
||||
let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 500, height: 300),
|
||||
styleMask: [.titled, .closable, .resizable],
|
||||
backing: .buffered, defer: false)
|
||||
window.title = "Software Update"
|
||||
window.title = "V2rayU Update"
|
||||
window.contentView = contentView
|
||||
|
||||
super.init(window: window)
|
||||
@@ -272,19 +306,37 @@ class AppVersionController: NSWindowController {
|
||||
}
|
||||
|
||||
func show(release: GithubRelease) {
|
||||
bindData.title = "A new version of V2rayU is available!"
|
||||
bindData.description = "V2rayU \(appVersion) is now available—you have \(release.tagName). Would you like to download it now?"
|
||||
bindData.releaseNotes = release.name + "\n" + release.body
|
||||
self.release = release
|
||||
print("bindData.releaseNotes", bindData.releaseNotes)
|
||||
// bring window to front
|
||||
window?.orderFrontRegardless()
|
||||
// center position
|
||||
window?.center()
|
||||
// make window key
|
||||
window?.makeKeyAndOrderFront(nil)
|
||||
// activate app
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
DispatchQueue.main.async {
|
||||
self.release = release
|
||||
if isMainland {
|
||||
self.bindData.title = "A new version of V2rayU is available!"
|
||||
if release.prerelease{
|
||||
self.bindData.description = "V2rayU \(release.tagName) preview is now available, you have \(appVersion). Would you like to download it now?"
|
||||
} else {
|
||||
self.bindData.description = "V2rayU \(release.tagName) is now available, you have \(appVersion). Would you like to download it now?"
|
||||
}
|
||||
self.bindData.releaseNotes = release.name + "\n" + release.body
|
||||
} else {
|
||||
self.bindData.title = "V2rayU 有新版本上线了!"
|
||||
if release.prerelease {
|
||||
self.bindData.description = "V2rayU 已上线 \(release.tagName) 预览版,您有的版本 \(appVersion) —,需要立即下载吗?"
|
||||
} else {
|
||||
self.bindData.description = "V2rayU 已上线 \(release.tagName),您有的版本 \(appVersion) —,需要立即下载吗?"
|
||||
}
|
||||
self.bindData.releaseNotes = release.name + "\n" + release.body
|
||||
self.bindData.releaseNodesTitle = "更新日志"
|
||||
self.bindData.skipVersion = "跳过此版本"
|
||||
self.bindData.installUpdate = "安装此版本"
|
||||
}
|
||||
// bring window to front
|
||||
self.window?.orderFrontRegardless()
|
||||
// center position
|
||||
self.window?.center()
|
||||
// make window key
|
||||
self.window?.makeKeyAndOrderFront(nil)
|
||||
// activate app
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
@@ -309,10 +361,10 @@ class AppVersionController: NSWindowController {
|
||||
|
||||
func skipAction() {
|
||||
print("Skip action")
|
||||
// UserDefaults 记录是否跳过版本更新
|
||||
UserDefaults.standard.set(release.tagName, forKey: "skipAppVersion")
|
||||
// 关闭窗口
|
||||
DispatchQueue.main.async {
|
||||
// UserDefaults 记录是否跳过版本更新
|
||||
UserDefaults.standard.set(self.release.tagName, forKey: "skipAppVersion")
|
||||
// 关闭窗口
|
||||
self.window?.close()
|
||||
}
|
||||
}
|
||||
@@ -320,8 +372,10 @@ class AppVersionController: NSWindowController {
|
||||
class BindData: ObservableObject {
|
||||
@Published var title = "A new version of V2rayU App is available!"
|
||||
@Published var description = ""
|
||||
@Published var releaseNotes = """
|
||||
"""
|
||||
@Published var releaseNotes = ""
|
||||
@Published var releaseNodesTitle = "Release Notes:"
|
||||
@Published var skipVersion = "Skip This Version!"
|
||||
@Published var installUpdate = "Install Update!"
|
||||
}
|
||||
|
||||
struct ContentView: View {
|
||||
@@ -347,7 +401,7 @@ class AppVersionController: NSWindowController {
|
||||
Text(bindData.description)
|
||||
.padding(.trailing, 20)
|
||||
|
||||
Text("Release Notes:")
|
||||
Text(bindData.releaseNodesTitle)
|
||||
.font(.headline)
|
||||
.bold()
|
||||
.padding(.top, 20)
|
||||
@@ -364,22 +418,25 @@ class AppVersionController: NSWindowController {
|
||||
|
||||
Spacer(minLength: 20) // 右边 margin 40
|
||||
}
|
||||
|
||||
HStack {
|
||||
Button(bindData.skipVersion) {
|
||||
skipAction()
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(bindData.installUpdate) {
|
||||
installAction()
|
||||
}
|
||||
.padding(.trailing, 20)
|
||||
.keyboardShortcut(.defaultAction)
|
||||
}
|
||||
.padding(.top,20)
|
||||
.padding(.bottom,20)
|
||||
}
|
||||
}
|
||||
|
||||
HStack {
|
||||
Button("Skip This Version") {
|
||||
skipAction()
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Button("Install Update") {
|
||||
installAction()
|
||||
}
|
||||
.keyboardShortcut(.defaultAction)
|
||||
}
|
||||
.padding(20)
|
||||
}
|
||||
.frame(width: 500, height: 300)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21225" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21225"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22690"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
@@ -51,7 +51,7 @@
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LeF-Sd-TXL">
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LeF-Sd-TXL">
|
||||
<rect key="frame" x="18" y="319" width="295" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="V2ray Dns Json Text:" id="W0g-B7-neT">
|
||||
@@ -82,7 +82,7 @@
|
||||
<action selector="save:" target="-2" id="ec3-n0-TCm"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="f4X-IX-Vz3" userLabel="Set the rules line by line: domain or ip">
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="f4X-IX-Vz3" userLabel="Set the rules line by line: domain or ip">
|
||||
<rect key="frame" x="18" y="22" width="251" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="* Please input v2ray DnsObject json text" id="yfy-JP-THq" userLabel="Set the rules line by line: domain or ip">
|
||||
@@ -91,7 +91,7 @@
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="HDw-wR-poM">
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="HDw-wR-poM">
|
||||
<rect key="frame" x="18" y="343" width="424" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" id="ztP-ok-6QX">
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>AppIcon</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string></string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<true/>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string></string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>AppIcon</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
// Copyright © 2019 yanue. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftyJSON
|
||||
|
||||
// ping and choose fastest v2ray
|
||||
var inPing = false
|
||||
var inPingCurrent = false
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
import Cocoa
|
||||
import Preferences
|
||||
import SwiftyJSON
|
||||
|
||||
final class PreferenceSubscribeViewController: NSViewController, PreferencePane, NSTabViewDelegate {
|
||||
let preferencePaneIdentifier = PreferencePane.Identifier.subscribeTab
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
import Cocoa
|
||||
import SystemConfiguration
|
||||
import Swifter
|
||||
import Alamofire
|
||||
|
||||
let LAUNCH_AGENT_NAME = "yanue.v2rayu.v2ray-core"
|
||||
let AppResourcesPath = Bundle.main.bundlePath + "/Contents/Resources"
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import SwiftyJSON
|
||||
|
||||
// ----- v2ray server manager -----
|
||||
class V2rayServer: NSObject {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import SwiftyJSON
|
||||
import Yams
|
||||
|
||||
// ----- v2ray subscribe manager -----
|
||||
|
||||
@@ -5,4 +5,3 @@
|
||||
Created by yanue on 2019/7/17.
|
||||
Copyright © 2019 yanue. All rights reserved.
|
||||
*/
|
||||
// Localizable App Name是App在英语环境环境下显示的名称
|
||||
|
||||
@@ -5,4 +5,3 @@
|
||||
Created by yanue on 2019/7/17.
|
||||
Copyright © 2019 yanue. All rights reserved.
|
||||
*/
|
||||
// Localizable App Name是App在英语环境环境下显示的名称
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Domain Strategy:"; ObjectID = "22k-l7-G7a"; */
|
||||
"22k-l7-G7a.title" = "域名策略:";
|
||||
/* Class = "NSTextFieldCell"; title = "Block:"; ObjectID = "0Cd-bg-07K"; */
|
||||
"0Cd-bg-07K.title" = "Block:";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Bypassing LAN and mainland address"; ObjectID = "3qq-dt-TS9"; */
|
||||
"3qq-dt-TS9.title" = "绕过局域网和大陆地址";
|
||||
/* Class = "NSMenuItem"; title = "IPOnDemand"; ObjectID = "2ST-s0-RrI"; */
|
||||
"2ST-s0-RrI.title" = "IPOnDemand";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Routing Rule:"; ObjectID = "4rB-9k-291"; */
|
||||
"4rB-9k-291.title" = "路由模式:";
|
||||
/* Class = "NSTextFieldCell"; title = "Direct:"; ObjectID = "3hZ-qS-PUG"; */
|
||||
"3hZ-qS-PUG.title" = "Direct:";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "save"; ObjectID = "8g2-Nj-m07"; */
|
||||
"8g2-Nj-m07.title" = "保存";
|
||||
"8g2-Nj-m07.title" = "save";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "IPIfNonMatch"; ObjectID = "92h-JU-wqn"; */
|
||||
"92h-JU-wqn.title" = "IPIfNonMatch";
|
||||
/* Class = "NSTextFieldCell"; title = "Rouing Rules"; ObjectID = "E4W-rN-0eq"; */
|
||||
"E4W-rN-0eq.title" = "Rouing Rules";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Bypassing the LAN Address"; ObjectID = "CoE-cp-7fn"; */
|
||||
"CoE-cp-7fn.title" = "绕过局域网地址";
|
||||
/* Class = "NSTextFieldCell"; title = "Custom Rule Name"; ObjectID = "Ecy-wl-v5i"; */
|
||||
"Ecy-wl-v5i.title" = "Custom Rule Name";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Bypassing mainland address"; ObjectID = "EaD-tR-ldB"; */
|
||||
"EaD-tR-ldB.title" = "绕过大陆地址";
|
||||
/* Class = "NSTextFieldCell"; title = "Routing Rule:"; ObjectID = "J2T-Pf-s5D"; */
|
||||
"J2T-Pf-s5D.title" = "Routing Rule:";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "IPOnDemand"; ObjectID = "Js7-cb-bWa"; */
|
||||
"Js7-cb-bWa.title" = "IPOnDemand";
|
||||
/* Class = "NSMenuItem"; title = "AsIs"; ObjectID = "Kl2-gr-bsh"; */
|
||||
"Kl2-gr-bsh.title" = "AsIs";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "AsIs"; ObjectID = "LX1-ye-51i"; */
|
||||
"LX1-ye-51i.title" = "AsIs";
|
||||
/* Class = "NSTextFieldCell"; title = "Custom Rule JSON Text"; ObjectID = "Q0v-Ic-TRt"; */
|
||||
"Q0v-Ic-TRt.title" = "Custom Rule JSON Text";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "load default"; ObjectID = "RSN-g5-vmP"; */
|
||||
"RSN-g5-vmP.title" = "load default";
|
||||
/* Class = "NSTextFieldCell"; title = "Domain Strategy:"; ObjectID = "Qp3-K0-xA9"; */
|
||||
"Qp3-K0-xA9.title" = "Domain Strategy:";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "* Set the rules line by line: domain or ip"; ObjectID = "ccq-gn-C6Z"; */
|
||||
"ccq-gn-C6Z.title" = "*按行设置域名或ip";
|
||||
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "YQ1-7i-YOl"; */
|
||||
"YQ1-7i-YOl.title" = "Text Cell";
|
||||
|
||||
/* Class = "NSTabViewItem"; label = "Block"; ObjectID = "nsT-BW-R2Z"; */
|
||||
"nsT-BW-R2Z.label" = "阻止ip或域名";
|
||||
/* Class = "NSTextFieldCell"; title = "Proxy:"; ObjectID = "cfS-8I-8Au"; */
|
||||
"cfS-8I-8Au.title" = "Proxy:";
|
||||
|
||||
/* Class = "NSTabViewItem"; label = "Proxy"; ObjectID = "pnL-Z8-fIK"; */
|
||||
"pnL-Z8-fIK.label" = "代理ip或域名";
|
||||
/* Class = "NSMenuItem"; title = "IPIfNonMatch"; ObjectID = "dSb-GT-n2n"; */
|
||||
"dSb-GT-n2n.title" = "IPIfNonMatch";
|
||||
|
||||
/* Class = "NSTabViewItem"; label = "Direct"; ObjectID = "yc0-Po-cG1"; */
|
||||
"yc0-Po-cG1.label" = "直连ip或域名";
|
||||
/* Class = "NSTextFieldCell"; title = "like: { \"domainStrategy\": \"IPOnDemand\", \"rules\": []}"; ObjectID = "ejH-X7-8Fb"; */
|
||||
"ejH-X7-8Fb.title" = "like: { \"domainStrategy\": \"IPOnDemand\", \"rules\": []}";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Global"; ObjectID = "zLf-pT-xlm"; */
|
||||
"zLf-pT-xlm.title" = "全局";
|
||||
/* Class = "NSTextFieldCell"; title = "* Set the rules line by line: domain or ip"; ObjectID = "ymo-ds-No9"; */
|
||||
"ymo-ds-No9.title" = "* Set the rules line by line: domain or ip";
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Domain Strategy:"; ObjectID = "22k-l7-G7a"; */
|
||||
"22k-l7-G7a.title" = "域名策略:";
|
||||
/* Class = "NSTextFieldCell"; title = "Block:"; ObjectID = "0Cd-bg-07K"; */
|
||||
"0Cd-bg-07K.title" = "阻止ip或域名:";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Bypassing LAN and mainland address"; ObjectID = "3qq-dt-TS9"; */
|
||||
"3qq-dt-TS9.title" = "绕过局域网和大陆地址";
|
||||
/* Class = "NSMenuItem"; title = "IPOnDemand"; ObjectID = "2ST-s0-RrI"; */
|
||||
"2ST-s0-RrI.title" = "IPOnDemand";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Routing Rule:"; ObjectID = "4rB-9k-291"; */
|
||||
"4rB-9k-291.title" = "路由模式:";
|
||||
/* Class = "NSTextFieldCell"; title = "Direct:"; ObjectID = "3hZ-qS-PUG"; */
|
||||
"3hZ-qS-PUG.title" = "直连ip或域名:";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "save"; ObjectID = "8g2-Nj-m07"; */
|
||||
"8g2-Nj-m07.title" = "保存";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "IPIfNonMatch"; ObjectID = "92h-JU-wqn"; */
|
||||
"92h-JU-wqn.title" = "IPIfNonMatch";
|
||||
/* Class = "NSTextFieldCell"; title = "Rouing Rules"; ObjectID = "E4W-rN-0eq"; */
|
||||
"E4W-rN-0eq.title" = "路由规则列表";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Bypassing the LAN Address"; ObjectID = "CoE-cp-7fn"; */
|
||||
"CoE-cp-7fn.title" = "绕过局域网地址";
|
||||
/* Class = "NSTextFieldCell"; title = "Custom Rule Name"; ObjectID = "Ecy-wl-v5i"; */
|
||||
"Ecy-wl-v5i.title" = "自定义路由名称";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Bypassing mainland address"; ObjectID = "EaD-tR-ldB"; */
|
||||
"EaD-tR-ldB.title" = "绕过大陆地址";
|
||||
/* Class = "NSTextFieldCell"; title = "Routing Rule:"; ObjectID = "J2T-Pf-s5D"; */
|
||||
"J2T-Pf-s5D.title" = "路由规则:";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "IPOnDemand"; ObjectID = "Js7-cb-bWa"; */
|
||||
"Js7-cb-bWa.title" = "IPOnDemand";
|
||||
/* Class = "NSMenuItem"; title = "AsIs"; ObjectID = "Kl2-gr-bsh"; */
|
||||
"Kl2-gr-bsh.title" = "AsIs";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "AsIs"; ObjectID = "LX1-ye-51i"; */
|
||||
"LX1-ye-51i.title" = "AsIs";
|
||||
/* Class = "NSTextFieldCell"; title = "Custom Rule JSON Text"; ObjectID = "Q0v-Ic-TRt"; */
|
||||
"Q0v-Ic-TRt.title" = "自定义路由 json 内容";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "load default"; ObjectID = "RSN-g5-vmP"; */
|
||||
"RSN-g5-vmP.title" = "load default";
|
||||
/* Class = "NSTextFieldCell"; title = "Domain Strategy:"; ObjectID = "Qp3-K0-xA9"; */
|
||||
"Qp3-K0-xA9.title" = "域名策略:";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "* Set the rules line by line: domain or ip"; ObjectID = "ccq-gn-C6Z"; */
|
||||
"ccq-gn-C6Z.title" = "*按行设置域名或ip";
|
||||
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "YQ1-7i-YOl"; */
|
||||
"YQ1-7i-YOl.title" = "";
|
||||
|
||||
/* Class = "NSTabViewItem"; label = "Block"; ObjectID = "nsT-BW-R2Z"; */
|
||||
"nsT-BW-R2Z.label" = "阻止ip或域名";
|
||||
/* Class = "NSTextFieldCell"; title = "Proxy:"; ObjectID = "cfS-8I-8Au"; */
|
||||
"cfS-8I-8Au.title" = "代理ip或域名:";
|
||||
|
||||
/* Class = "NSTabViewItem"; label = "Proxy"; ObjectID = "pnL-Z8-fIK"; */
|
||||
"pnL-Z8-fIK.label" = "代理ip或域名";
|
||||
/* Class = "NSMenuItem"; title = "IPIfNonMatch"; ObjectID = "dSb-GT-n2n"; */
|
||||
"dSb-GT-n2n.title" = "IPIfNonMatch";
|
||||
|
||||
/* Class = "NSTabViewItem"; label = "Direct"; ObjectID = "yc0-Po-cG1"; */
|
||||
"yc0-Po-cG1.label" = "直连ip或域名";
|
||||
/* Class = "NSTextFieldCell"; title = "like: { \"domainStrategy\": \"IPOnDemand\", \"rules\": []}"; ObjectID = "ejH-X7-8Fb"; */
|
||||
"ejH-X7-8Fb.title" = "例如: { \"domainStrategy\": \"IPOnDemand\", \"rules\": []}";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Global"; ObjectID = "zLf-pT-xlm"; */
|
||||
"zLf-pT-xlm.title" = "全局";
|
||||
/* Class = "NSTextFieldCell"; title = "* Set the rules line by line: domain or ip"; ObjectID = "ymo-ds-No9"; */
|
||||
"ymo-ds-No9.title" = "* 按行设置域名或ip";
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ require (
|
||||
golang.org/x/crypto v0.24.0
|
||||
golang.org/x/net v0.26.0
|
||||
golang.org/x/sync v0.7.0
|
||||
golang.org/x/sys v0.21.0
|
||||
golang.org/x/sys v0.22.0
|
||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
||||
google.golang.org/grpc v1.65.0
|
||||
google.golang.org/protobuf v1.34.2
|
||||
|
||||
+2
-2
@@ -226,8 +226,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
||||
@@ -120,6 +120,7 @@ class YandexMusicTrackIE(YandexMusicBaseIE):
|
||||
download_data = self._download_json(
|
||||
'https://music.yandex.ru/api/v2.1/handlers/track/%s:%s/web-album_track-track-track-main/download/m' % (track_id, album_id),
|
||||
track_id, 'Downloading track location url JSON',
|
||||
query={'hq': 1},
|
||||
headers={'X-Retpath-Y': url})
|
||||
|
||||
fd_data = self._download_json(
|
||||
|
||||
@@ -2324,6 +2324,7 @@ from .vidio import (
|
||||
)
|
||||
from .vidlii import VidLiiIE
|
||||
from .vidly import VidlyIE
|
||||
from .vidyard import VidyardIE
|
||||
from .viewlift import (
|
||||
ViewLiftEmbedIE,
|
||||
ViewLiftIE,
|
||||
|
||||
@@ -368,6 +368,7 @@ class AbemaTVIE(AbemaTVBaseIE):
|
||||
info['episode_number'] = epis if epis < 2000 else None
|
||||
|
||||
is_live, m3u8_url = False, None
|
||||
availability = 'public'
|
||||
if video_type == 'now-on-air':
|
||||
is_live = True
|
||||
channel_url = 'https://api.abema.io/v1/channels'
|
||||
@@ -389,6 +390,7 @@ class AbemaTVIE(AbemaTVBaseIE):
|
||||
if 3 not in ondemand_types:
|
||||
# cannot acquire decryption key for these streams
|
||||
self.report_warning('This is a premium-only stream')
|
||||
availability = 'premium_only'
|
||||
info.update(traverse_obj(api_response, {
|
||||
'series': ('series', 'title'),
|
||||
'season': ('season', 'name'),
|
||||
@@ -408,6 +410,7 @@ class AbemaTVIE(AbemaTVBaseIE):
|
||||
headers=headers)
|
||||
if not traverse_obj(api_response, ('slot', 'flags', 'timeshiftFree'), default=False):
|
||||
self.report_warning('This is a premium-only stream')
|
||||
availability = 'premium_only'
|
||||
|
||||
m3u8_url = f'https://vod-abematv.akamaized.net/slot/{video_id}/playlist.m3u8'
|
||||
else:
|
||||
@@ -425,6 +428,7 @@ class AbemaTVIE(AbemaTVBaseIE):
|
||||
'description': description,
|
||||
'formats': formats,
|
||||
'is_live': is_live,
|
||||
'availability': availability,
|
||||
})
|
||||
return info
|
||||
|
||||
|
||||
@@ -1,63 +1,50 @@
|
||||
from .common import InfoExtractor
|
||||
from ..utils import traverse_obj
|
||||
from .vidyard import VidyardBaseIE, VidyardIE
|
||||
from ..utils import ExtractorError, make_archive_id, url_basename
|
||||
|
||||
|
||||
class CellebriteIE(InfoExtractor):
|
||||
class CellebriteIE(VidyardBaseIE):
|
||||
_VALID_URL = r'https?://cellebrite\.com/(?:\w+)?/(?P<id>[\w-]+)'
|
||||
_TESTS = [{
|
||||
'url': 'https://cellebrite.com/en/collect-data-from-android-devices-with-cellebrite-ufed/',
|
||||
'info_dict': {
|
||||
'id': '16025876',
|
||||
'id': 'ZqmUss3dQfEMGpauambPuH',
|
||||
'display_id': '16025876',
|
||||
'ext': 'mp4',
|
||||
'description': 'md5:174571cb97083fd1d457d75c684f4e2b',
|
||||
'thumbnail': 'https://cellebrite.com/wp-content/uploads/2021/05/Chat-Capture-1024x559.png',
|
||||
'title': 'Ask the Expert: Chat Capture - Collect Data from Android Devices in Cellebrite UFED',
|
||||
'duration': 455,
|
||||
'tags': [],
|
||||
'description': 'md5:dee48fe12bbae5c01fe6a053f7676da4',
|
||||
'thumbnail': 'https://cellebrite.com/wp-content/uploads/2021/05/Chat-Capture-1024x559.png',
|
||||
'duration': 455.979,
|
||||
'_old_archive_ids': ['cellebrite 16025876'],
|
||||
},
|
||||
}, {
|
||||
'url': 'https://cellebrite.com/en/how-to-lawfully-collect-the-maximum-amount-of-data-from-android-devices/',
|
||||
'info_dict': {
|
||||
'id': '29018255',
|
||||
'id': 'QV1U8a2yzcxigw7VFnqKyg',
|
||||
'display_id': '29018255',
|
||||
'ext': 'mp4',
|
||||
'duration': 134,
|
||||
'tags': [],
|
||||
'description': 'md5:e9a3d124c7287b0b07bad2547061cacf',
|
||||
'title': 'How to Lawfully Collect the Maximum Amount of Data From Android Devices',
|
||||
'description': 'md5:0e943a9ac14c374d5d74faed634d773c',
|
||||
'thumbnail': 'https://cellebrite.com/wp-content/uploads/2022/07/How-to-Lawfully-Collect-the-Maximum-Amount-of-Data-From-Android-Devices.png',
|
||||
'title': 'Android Extractions Explained',
|
||||
'duration': 134.315,
|
||||
'_old_archive_ids': ['cellebrite 29018255'],
|
||||
},
|
||||
}]
|
||||
|
||||
def _get_formats_and_subtitles(self, json_data, display_id):
|
||||
formats = [{'url': url} for url in traverse_obj(json_data, ('mp4', ..., 'url')) or []]
|
||||
subtitles = {}
|
||||
|
||||
for url in traverse_obj(json_data, ('hls', ..., 'url')) or []:
|
||||
fmt, sub = self._extract_m3u8_formats_and_subtitles(
|
||||
url, display_id, ext='mp4', headers={'Referer': 'https://play.vidyard.com/'})
|
||||
formats.extend(fmt)
|
||||
self._merge_subtitles(sub, target=subtitles)
|
||||
|
||||
return formats, subtitles
|
||||
|
||||
def _real_extract(self, url):
|
||||
display_id = self._match_id(url)
|
||||
webpage = self._download_webpage(url, display_id)
|
||||
slug = self._match_id(url)
|
||||
webpage = self._download_webpage(url, slug)
|
||||
vidyard_url = next(VidyardIE._extract_embed_urls(url, webpage), None)
|
||||
if not vidyard_url:
|
||||
raise ExtractorError('No Vidyard video embeds found on page')
|
||||
|
||||
player_uuid = self._search_regex(
|
||||
r'<img\s[^>]*\bdata-uuid\s*=\s*"([^"\?]+)', webpage, 'player UUID')
|
||||
json_data = self._download_json(
|
||||
f'https://play.vidyard.com/player/{player_uuid}.json', display_id)['payload']['chapters'][0]
|
||||
video_id = url_basename(vidyard_url)
|
||||
info = self._process_video_json(self._fetch_video_json(video_id)['chapters'][0], video_id)
|
||||
if info.get('display_id'):
|
||||
info['_old_archive_ids'] = [make_archive_id(self, info['display_id'])]
|
||||
if thumbnail := self._og_search_thumbnail(webpage, default=None):
|
||||
info.setdefault('thumbnails', []).append({'url': thumbnail})
|
||||
|
||||
formats, subtitles = self._get_formats_and_subtitles(json_data['sources'], display_id)
|
||||
return {
|
||||
'id': str(json_data['videoId']),
|
||||
'title': json_data.get('name') or self._og_search_title(webpage),
|
||||
'formats': formats,
|
||||
'subtitles': subtitles,
|
||||
'description': json_data.get('description') or self._og_search_description(webpage),
|
||||
'duration': json_data.get('seconds'),
|
||||
'tags': json_data.get('tags'),
|
||||
'thumbnail': self._og_search_thumbnail(webpage),
|
||||
'http_headers': {'Referer': 'https://play.vidyard.com/'},
|
||||
'description': self._og_search_description(webpage, default=None),
|
||||
**info,
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class CHZZKLiveIE(InfoExtractor):
|
||||
def _real_extract(self, url):
|
||||
channel_id = self._match_id(url)
|
||||
live_detail = self._download_json(
|
||||
f'https://api.chzzk.naver.com/service/v2/channels/{channel_id}/live-detail', channel_id,
|
||||
f'https://api.chzzk.naver.com/service/v3/channels/{channel_id}/live-detail', channel_id,
|
||||
note='Downloading channel info', errnote='Unable to download channel info')['content']
|
||||
|
||||
if live_detail.get('status') == 'CLOSE':
|
||||
@@ -106,12 +106,45 @@ class CHZZKVideoIE(InfoExtractor):
|
||||
'upload_date': '20231219',
|
||||
'view_count': int,
|
||||
},
|
||||
'skip': 'Replay video is expired',
|
||||
}, {
|
||||
# Manually uploaded video
|
||||
'url': 'https://chzzk.naver.com/video/1980',
|
||||
'info_dict': {
|
||||
'id': '1980',
|
||||
'ext': 'mp4',
|
||||
'title': '※시청주의※한번보면 잊기 힘든 영상',
|
||||
'channel': '라디유radiyu',
|
||||
'channel_id': '68f895c59a1043bc5019b5e08c83a5c5',
|
||||
'channel_is_verified': False,
|
||||
'thumbnail': r're:^https?://.*\.jpg$',
|
||||
'duration': 95,
|
||||
'timestamp': 1703102631.722,
|
||||
'upload_date': '20231220',
|
||||
'view_count': int,
|
||||
},
|
||||
}, {
|
||||
# Partner channel replay video
|
||||
'url': 'https://chzzk.naver.com/video/2458',
|
||||
'info_dict': {
|
||||
'id': '2458',
|
||||
'ext': 'mp4',
|
||||
'title': '첫 방송',
|
||||
'channel': '강지',
|
||||
'channel_id': 'b5ed5db484d04faf4d150aedd362f34b',
|
||||
'channel_is_verified': True,
|
||||
'thumbnail': r're:^https?://.*\.jpg$',
|
||||
'duration': 4433,
|
||||
'timestamp': 1703307460.214,
|
||||
'upload_date': '20231223',
|
||||
'view_count': int,
|
||||
},
|
||||
}]
|
||||
|
||||
def _real_extract(self, url):
|
||||
video_id = self._match_id(url)
|
||||
video_meta = self._download_json(
|
||||
f'https://api.chzzk.naver.com/service/v2/videos/{video_id}', video_id,
|
||||
f'https://api.chzzk.naver.com/service/v3/videos/{video_id}', video_id,
|
||||
note='Downloading video info', errnote='Unable to download video info')['content']
|
||||
formats, subtitles = self._extract_mpd_formats_and_subtitles(
|
||||
f'https://apis.naver.com/neonplayer/vodplay/v1/playback/{video_meta["videoId"]}', video_id,
|
||||
|
||||
@@ -1,55 +1,31 @@
|
||||
from .common import InfoExtractor
|
||||
from ..utils import ExtractorError, int_or_none, traverse_obj
|
||||
from .vidyard import VidyardBaseIE
|
||||
from ..utils import ExtractorError, int_or_none, make_archive_id
|
||||
|
||||
|
||||
class SwearnetEpisodeIE(InfoExtractor):
|
||||
class SwearnetEpisodeIE(VidyardBaseIE):
|
||||
_VALID_URL = r'https?://www\.swearnet\.com/shows/(?P<id>[\w-]+)/seasons/(?P<season_num>\d+)/episodes/(?P<episode_num>\d+)'
|
||||
_TESTS = [{
|
||||
'url': 'https://www.swearnet.com/shows/gettin-learnt-with-ricky/seasons/1/episodes/1',
|
||||
'info_dict': {
|
||||
'id': '232819',
|
||||
'id': 'wicK2EOzjOdxkUXGDIgcPw',
|
||||
'display_id': '232819',
|
||||
'ext': 'mp4',
|
||||
'episode_number': 1,
|
||||
'episode': 'Episode 1',
|
||||
'duration': 719,
|
||||
'description': 'md5:c48ef71440ce466284c07085cd7bd761',
|
||||
'description': r're:Are you drunk and high and craving a grilled cheese sandwich.+',
|
||||
'season': 'Season 1',
|
||||
'title': 'Episode 1 - Grilled Cheese Sammich',
|
||||
'season_number': 1,
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/232819/_RX04IKIq60a2V6rIRqq_Q_small.jpg',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/custom/0dd74f9b-388a-452e-b570-b407fb64435b_small.jpg',
|
||||
'tags': ['Getting Learnt with Ricky', 'drunk', 'grilled cheese', 'high'],
|
||||
'_old_archive_ids': ['swearnetepisode 232819'],
|
||||
},
|
||||
}]
|
||||
|
||||
def _get_formats_and_subtitle(self, video_source, video_id):
|
||||
video_source = video_source or {}
|
||||
formats, subtitles = [], {}
|
||||
for key, value in video_source.items():
|
||||
if key == 'hls':
|
||||
for video_hls in value:
|
||||
fmts, subs = self._extract_m3u8_formats_and_subtitles(video_hls.get('url'), video_id)
|
||||
formats.extend(fmts)
|
||||
self._merge_subtitles(subs, target=subtitles)
|
||||
else:
|
||||
formats.extend({
|
||||
'url': video_mp4.get('url'),
|
||||
'ext': 'mp4',
|
||||
} for video_mp4 in value)
|
||||
|
||||
return formats, subtitles
|
||||
|
||||
def _get_direct_subtitle(self, caption_json):
|
||||
subs = {}
|
||||
for caption in caption_json:
|
||||
subs.setdefault(caption.get('language') or 'und', []).append({
|
||||
'url': caption.get('vttUrl'),
|
||||
'name': caption.get('name'),
|
||||
})
|
||||
|
||||
return subs
|
||||
|
||||
def _real_extract(self, url):
|
||||
display_id, season_number, episode_number = self._match_valid_url(url).group('id', 'season_num', 'episode_num')
|
||||
webpage = self._download_webpage(url, display_id)
|
||||
slug, season_number, episode_number = self._match_valid_url(url).group('id', 'season_num', 'episode_num')
|
||||
webpage = self._download_webpage(url, slug)
|
||||
|
||||
try:
|
||||
external_id = self._search_regex(r'externalid\s*=\s*"([^"]+)', webpage, 'externalid')
|
||||
@@ -58,22 +34,12 @@ class SwearnetEpisodeIE(InfoExtractor):
|
||||
self.raise_login_required()
|
||||
raise
|
||||
|
||||
json_data = self._download_json(
|
||||
f'https://play.vidyard.com/player/{external_id}.json', display_id)['payload']['chapters'][0]
|
||||
|
||||
formats, subtitles = self._get_formats_and_subtitle(json_data['sources'], display_id)
|
||||
self._merge_subtitles(self._get_direct_subtitle(json_data.get('captions')), target=subtitles)
|
||||
info = self._process_video_json(self._fetch_video_json(external_id)['chapters'][0], external_id)
|
||||
if info.get('display_id'):
|
||||
info['_old_archive_ids'] = [make_archive_id(self, info['display_id'])]
|
||||
|
||||
return {
|
||||
'id': str(json_data['videoId']),
|
||||
'title': json_data.get('name') or self._html_search_meta(['og:title', 'twitter:title'], webpage),
|
||||
'description': (json_data.get('description')
|
||||
or self._html_search_meta(['og:description', 'twitter:description'], webpage)),
|
||||
'duration': int_or_none(json_data.get('seconds')),
|
||||
'formats': formats,
|
||||
'subtitles': subtitles,
|
||||
**info,
|
||||
'season_number': int_or_none(season_number),
|
||||
'episode_number': int_or_none(episode_number),
|
||||
'thumbnails': [{'url': thumbnail_url}
|
||||
for thumbnail_url in traverse_obj(json_data, ('thumbnailUrls', ...))],
|
||||
}
|
||||
|
||||
@@ -0,0 +1,426 @@
|
||||
import functools
|
||||
import re
|
||||
|
||||
from .common import InfoExtractor
|
||||
from ..utils import (
|
||||
extract_attributes,
|
||||
float_or_none,
|
||||
int_or_none,
|
||||
join_nonempty,
|
||||
mimetype2ext,
|
||||
parse_resolution,
|
||||
str_or_none,
|
||||
unescapeHTML,
|
||||
url_or_none,
|
||||
)
|
||||
from ..utils.traversal import traverse_obj
|
||||
|
||||
|
||||
class VidyardBaseIE(InfoExtractor):
|
||||
_HEADERS = {'Referer': 'https://play.vidyard.com/'}
|
||||
|
||||
def _get_formats_and_subtitles(self, sources, video_id):
|
||||
formats, subtitles = [], {}
|
||||
|
||||
def add_hls_fmts_and_subs(m3u8_url):
|
||||
fmts, subs = self._extract_m3u8_formats_and_subtitles(
|
||||
m3u8_url, video_id, 'mp4', m3u8_id='hls', headers=self._HEADERS, fatal=False)
|
||||
formats.extend(fmts)
|
||||
self._merge_subtitles(subs, target=subtitles)
|
||||
|
||||
hls_list = isinstance(sources, dict) and sources.pop('hls', None)
|
||||
if master_m3u8_url := traverse_obj(
|
||||
hls_list, (lambda _, v: v['profile'] == 'auto', 'url', {url_or_none}, any)):
|
||||
add_hls_fmts_and_subs(master_m3u8_url)
|
||||
if not formats: # These are duplicate and unnecesary requests if we got 'auto' hls fmts
|
||||
for variant_m3u8_url in traverse_obj(hls_list, (..., 'url', {url_or_none})):
|
||||
add_hls_fmts_and_subs(variant_m3u8_url)
|
||||
|
||||
for source_type, source_list in traverse_obj(sources, ({dict.items}, ...)):
|
||||
for source in traverse_obj(source_list, lambda _, v: url_or_none(v['url'])):
|
||||
profile = source.get('profile')
|
||||
formats.append({
|
||||
'url': source['url'],
|
||||
'ext': mimetype2ext(source.get('mimeType'), default=None),
|
||||
'format_id': join_nonempty('http', source_type, profile),
|
||||
**parse_resolution(profile),
|
||||
})
|
||||
|
||||
self._remove_duplicate_formats(formats)
|
||||
return formats, subtitles
|
||||
|
||||
def _get_direct_subtitles(self, caption_json):
|
||||
subs = {}
|
||||
for caption in traverse_obj(caption_json, lambda _, v: url_or_none(v['vttUrl'])):
|
||||
subs.setdefault(caption.get('language') or 'und', []).append({
|
||||
'url': caption['vttUrl'],
|
||||
'name': caption.get('name'),
|
||||
})
|
||||
|
||||
return subs
|
||||
|
||||
def _fetch_video_json(self, video_id):
|
||||
return self._download_json(
|
||||
f'https://play.vidyard.com/player/{video_id}.json', video_id)['payload']
|
||||
|
||||
def _process_video_json(self, json_data, video_id):
|
||||
formats, subtitles = self._get_formats_and_subtitles(json_data['sources'], video_id)
|
||||
self._merge_subtitles(self._get_direct_subtitles(json_data.get('captions')), target=subtitles)
|
||||
|
||||
return {
|
||||
**traverse_obj(json_data, {
|
||||
'id': ('facadeUuid', {str}),
|
||||
'display_id': ('videoId', {int}, {str_or_none}),
|
||||
'title': ('name', {str}),
|
||||
'description': ('description', {str}, {unescapeHTML}, {lambda x: x or None}),
|
||||
'duration': ((
|
||||
('milliseconds', {functools.partial(float_or_none, scale=1000)}),
|
||||
('seconds', {int_or_none})), any),
|
||||
'thumbnails': ('thumbnailUrls', ('small', 'normal'), {'url': {url_or_none}}),
|
||||
'tags': ('tags', ..., 'name', {str}),
|
||||
}),
|
||||
'formats': formats,
|
||||
'subtitles': subtitles,
|
||||
'http_headers': self._HEADERS,
|
||||
}
|
||||
|
||||
|
||||
class VidyardIE(VidyardBaseIE):
|
||||
_VALID_URL = [
|
||||
r'https?://[\w-]+(?:\.hubs)?\.vidyard\.com/watch/(?P<id>[\w-]+)',
|
||||
r'https?://(?:embed|share)\.vidyard\.com/share/(?P<id>[\w-]+)',
|
||||
r'https?://play\.vidyard\.com/(?:player/)?(?P<id>[\w-]+)',
|
||||
]
|
||||
_EMBED_REGEX = [r'<iframe[^>]* src=["\'](?P<url>(?:https?:)?//play\.vidyard\.com/[\w-]+)']
|
||||
_TESTS = [{
|
||||
'url': 'https://vyexample03.hubs.vidyard.com/watch/oTDMPlUv--51Th455G5u7Q',
|
||||
'info_dict': {
|
||||
'id': 'oTDMPlUv--51Th455G5u7Q',
|
||||
'display_id': '50347',
|
||||
'ext': 'mp4',
|
||||
'title': 'Homepage Video',
|
||||
'description': 'Look I changed the description.',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/50347/OUPa5LTKV46849sLYngMqQ_small.jpg',
|
||||
'duration': 99,
|
||||
'tags': ['these', 'are', 'all', 'tags'],
|
||||
},
|
||||
}, {
|
||||
'url': 'https://share.vidyard.com/watch/PaQzDAT1h8JqB8ivEu2j6Y?',
|
||||
'info_dict': {
|
||||
'id': 'PaQzDAT1h8JqB8ivEu2j6Y',
|
||||
'display_id': '9281024',
|
||||
'ext': 'mp4',
|
||||
'title': 'Inline Embed',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/spacer.gif',
|
||||
'duration': 41.186,
|
||||
},
|
||||
}, {
|
||||
'url': 'https://embed.vidyard.com/share/oTDMPlUv--51Th455G5u7Q',
|
||||
'info_dict': {
|
||||
'id': 'oTDMPlUv--51Th455G5u7Q',
|
||||
'display_id': '50347',
|
||||
'ext': 'mp4',
|
||||
'title': 'Homepage Video',
|
||||
'description': 'Look I changed the description.',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/50347/OUPa5LTKV46849sLYngMqQ_small.jpg',
|
||||
'duration': 99,
|
||||
'tags': ['these', 'are', 'all', 'tags'],
|
||||
},
|
||||
}, {
|
||||
# First video from playlist below
|
||||
'url': 'https://embed.vidyard.com/share/SyStyHtYujcBHe5PkZc5DL',
|
||||
'info_dict': {
|
||||
'id': 'SyStyHtYujcBHe5PkZc5DL',
|
||||
'display_id': '41974005',
|
||||
'ext': 'mp4',
|
||||
'title': 'Prepare the Frame and Track for Palm Beach Polysatin Shutters With BiFold Track',
|
||||
'description': r're:In this video, you will learn how to prepare the frame.+',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/41974005/IJw7oCaJcF1h7WWu3OVZ8A_small.png',
|
||||
'duration': 258.666,
|
||||
},
|
||||
}, {
|
||||
# Playlist
|
||||
'url': 'https://thelink.hubs.vidyard.com/watch/pwu7pCYWSwAnPxs8nDoFrE',
|
||||
'info_dict': {
|
||||
'id': 'pwu7pCYWSwAnPxs8nDoFrE',
|
||||
'title': 'PLAYLIST - Palm Beach Shutters- Bi-Fold Track System Installation',
|
||||
'entries': [{
|
||||
'id': 'SyStyHtYujcBHe5PkZc5DL',
|
||||
'display_id': '41974005',
|
||||
'ext': 'mp4',
|
||||
'title': 'Prepare the Frame and Track for Palm Beach Polysatin Shutters With BiFold Track',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/41974005/IJw7oCaJcF1h7WWu3OVZ8A_small.png',
|
||||
'duration': 258.666,
|
||||
}, {
|
||||
'id': '1Fw4B84jZTXLXWqkE71RiM',
|
||||
'display_id': '5861113',
|
||||
'ext': 'mp4',
|
||||
'title': 'Palm Beach - Bi-Fold Track System "Frame Installation"',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/5861113/29CJ54s5g1_aP38zkKLHew_small.jpg',
|
||||
'duration': 167.858,
|
||||
}, {
|
||||
'id': 'DqP3wBvLXSpxrcqpT5kEeo',
|
||||
'display_id': '41976334',
|
||||
'ext': 'mp4',
|
||||
'title': 'Install the Track for Palm Beach Polysatin Shutters With BiFold Track',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/5861090/RwG2VaTylUa6KhSTED1r1Q_small.png',
|
||||
'duration': 94.229,
|
||||
}, {
|
||||
'id': 'opfybfxpzQArxqtQYB6oBU',
|
||||
'display_id': '41976364',
|
||||
'ext': 'mp4',
|
||||
'title': 'Install the Panel for Palm Beach Polysatin Shutters With BiFold Track',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/5860926/JIOaJR08dM4QgXi_iQ2zGA_small.png',
|
||||
'duration': 191.467,
|
||||
}, {
|
||||
'id': 'rWrXvkbTNNaNqD6189HJya',
|
||||
'display_id': '41976382',
|
||||
'ext': 'mp4',
|
||||
'title': 'Adjust the Panels for Palm Beach Polysatin Shutters With BiFold Track',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/5860687/CwHxBv4UudAhOh43FVB4tw_small.png',
|
||||
'duration': 138.155,
|
||||
}, {
|
||||
'id': 'eYPTB521MZ9TPEArSethQ5',
|
||||
'display_id': '41976409',
|
||||
'ext': 'mp4',
|
||||
'title': 'Assemble and Install the Valance for Palm Beach Polysatin Shutters With BiFold Track',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/5861425/0y68qlMU4O5VKU7bJ8i_AA_small.png',
|
||||
'duration': 148.224,
|
||||
}],
|
||||
},
|
||||
'playlist_count': 6,
|
||||
}, {
|
||||
# Non hubs.vidyard.com playlist
|
||||
'url': 'https://salesforce.vidyard.com/watch/d4vqPjs7Q5EzVEis5QT3jd',
|
||||
'info_dict': {
|
||||
'id': 'd4vqPjs7Q5EzVEis5QT3jd',
|
||||
'title': 'How To: Service Cloud: Import External Content in Lightning Knowledge',
|
||||
'entries': [{
|
||||
'id': 'mcjDpSZir2iSttbvFkx6Rv',
|
||||
'display_id': '29479036',
|
||||
'ext': 'mp4',
|
||||
'title': 'Welcome to this Expert Coaching Series',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/ouyQi9WuwyiOupChUWNmjQ/7170d3485ba602e012df05_small.jpg',
|
||||
'duration': 38.205,
|
||||
}, {
|
||||
'id': '84bPYwpg243G6xYEfJdYw9',
|
||||
'display_id': '21820704',
|
||||
'ext': 'mp4',
|
||||
'title': 'Chapter 1 - Title + Agenda',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/HFPN0ZgQq4Ow8BghGcQSow/bfaa30123c8f6601e7d7f2_small.jpg',
|
||||
'duration': 98.016,
|
||||
}, {
|
||||
'id': 'nP17fMuvA66buVHUrzqjTi',
|
||||
'display_id': '21820707',
|
||||
'ext': 'mp4',
|
||||
'title': 'Chapter 2 - Import Options',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/rGRIF5nFjPI9OOA2qJ_Dbg/86a8d02bfec9a566845dd4_small.jpg',
|
||||
'duration': 199.136,
|
||||
}, {
|
||||
'id': 'm54EcwXdpA5gDBH5rgCYoV',
|
||||
'display_id': '21820710',
|
||||
'ext': 'mp4',
|
||||
'title': 'Chapter 3 - Importing Article Translations',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/IVX4XR8zpSsiNIHx45kz-A/1ccbf8a29a33856d06b3ed_small.jpg',
|
||||
'duration': 184.352,
|
||||
}, {
|
||||
'id': 'j4nzS42oq4hE9oRV73w3eQ',
|
||||
'display_id': '21820716',
|
||||
'ext': 'mp4',
|
||||
'title': 'Chapter 4 - Best Practices',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/BtrRrQpRDLbA4AT95YQyog/1f1e6b8e7fdc3fa95ec8d3_small.jpg',
|
||||
'duration': 296.960,
|
||||
}, {
|
||||
'id': 'y28PYfW5pftvers9PXzisC',
|
||||
'display_id': '21820727',
|
||||
'ext': 'mp4',
|
||||
'title': 'Chapter 5 - Migration Steps',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/K2CdQOXDfLcrVTF60r0bdw/a09239ada28b6ffce12b1f_small.jpg',
|
||||
'duration': 620.640,
|
||||
}, {
|
||||
'id': 'YWU1eQxYvhj29SjYoPw5jH',
|
||||
'display_id': '21820733',
|
||||
'ext': 'mp4',
|
||||
'title': 'Chapter 6 - Demo',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/rsmhP-cO8dAa8ilvFGCX0g/7911ef415167cd14032068_small.jpg',
|
||||
'duration': 631.456,
|
||||
}, {
|
||||
'id': 'nmEvVqpwdJUgb74zKsLGxn',
|
||||
'display_id': '29479037',
|
||||
'ext': 'mp4',
|
||||
'title': 'Schedule Your Follow-Up',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/Rtwc7X4PEkF4Ae5kHi-Jvw/174ebed3f34227b1ffa1d0_small.jpg',
|
||||
'duration': 33.608,
|
||||
}],
|
||||
},
|
||||
'playlist_count': 8,
|
||||
}, {
|
||||
# URL of iframe embed src
|
||||
'url': 'https://play.vidyard.com/iDqTwWGrd36vaLuaCY3nTs.html',
|
||||
'info_dict': {
|
||||
'id': 'iDqTwWGrd36vaLuaCY3nTs',
|
||||
'display_id': '9281009',
|
||||
'ext': 'mp4',
|
||||
'title': 'Lightbox Embed',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/spacer.gif',
|
||||
'duration': 39.035,
|
||||
},
|
||||
}, {
|
||||
# Player JSON URL
|
||||
'url': 'https://play.vidyard.com/player/7GAApnNNbcZZ46k6JqJQSh.json?disable_analytics=0',
|
||||
'info_dict': {
|
||||
'id': '7GAApnNNbcZZ46k6JqJQSh',
|
||||
'display_id': '820026',
|
||||
'ext': 'mp4',
|
||||
'title': 'The Art of Storytelling: How to Deliver Your Brand Story with Content & Social',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/MhbE-5sEFQu4x3fI6FkNlA/41eb5717c557cd19456910_small.jpg',
|
||||
'duration': 2153.013,
|
||||
'tags': ['Summit2017'],
|
||||
},
|
||||
}, {
|
||||
'url': 'http://share.vidyard.com/share/diYeo6YR2yiGgL8odvS8Ri',
|
||||
'only_matching': True,
|
||||
}, {
|
||||
'url': 'https://play.vidyard.com/FFlz3ZpxhIfKQ1fd9DAryA',
|
||||
'only_matching': True,
|
||||
}, {
|
||||
'url': 'https://play.vidyard.com/qhMAu5A76GZVrFzOPgSf9A/type/standalone',
|
||||
'only_matching': True,
|
||||
}]
|
||||
_WEBPAGE_TESTS = [{
|
||||
# URL containing inline/lightbox embedded video
|
||||
'url': 'https://resources.altium.com/p/2-the-extreme-importance-of-pc-board-stack-up',
|
||||
'info_dict': {
|
||||
'id': 'GDx1oXrFWj4XHbipfoXaMn',
|
||||
'display_id': '3225198',
|
||||
'ext': 'mp4',
|
||||
'title': 'The Extreme Importance of PC Board Stack Up',
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/73_Q3_hBexWX7Og1sae6cg/9998fa4faec921439e2c04_small.jpg',
|
||||
'duration': 3422.742,
|
||||
},
|
||||
}, {
|
||||
# <script ... id="vidyard_embed_code_DXx2sW4WaLA6hTdGFz7ja8" src="//play.vidyard.com/DXx2sW4WaLA6hTdGFz7ja8.js?
|
||||
'url': 'http://videos.vivint.com/watch/DXx2sW4WaLA6hTdGFz7ja8',
|
||||
'info_dict': {
|
||||
'id': 'DXx2sW4WaLA6hTdGFz7ja8',
|
||||
'display_id': '2746529',
|
||||
'ext': 'mp4',
|
||||
'title': 'How To Powercycle the Smart Hub Panel',
|
||||
'duration': 30.613,
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/_-6cw8xQUJ3qiCs_JENc_A/b21d7a5e47967f49399d30_small.jpg',
|
||||
},
|
||||
}, {
|
||||
# <script id="vidyard_embed_code_MIBHhiLVTxga7wqLsuoDjQ" src="//embed.vidyard.com/embed/MIBHhiLVTxga7wqLsuoDjQ/inline?v=2.1">
|
||||
'url': 'https://www.babypips.com/learn/forex/introduction-to-metatrader4',
|
||||
'info_dict': {
|
||||
'id': 'MIBHhiLVTxga7wqLsuoDjQ',
|
||||
'display_id': '20291',
|
||||
'ext': 'mp4',
|
||||
'title': 'Lesson 1 - Opening an MT4 Account',
|
||||
'description': 'Never heard of MetaTrader4? Here\'s the 411 on the popular trading platform!',
|
||||
'duration': 168,
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/20291/IM-G2WXQR9VBLl2Cmzvftg_small.jpg',
|
||||
},
|
||||
}, {
|
||||
# <iframe ... src="//play.vidyard.com/d61w8EQoZv1LDuPxDkQP2Q/type/background?preview=1"
|
||||
'url': 'https://www.avaya.com/en/',
|
||||
'info_dict': {
|
||||
# These values come from the generic extractor and don't matter
|
||||
'id': str,
|
||||
'title': str,
|
||||
'age_limit': 0,
|
||||
'upload_date': str,
|
||||
'description': str,
|
||||
'thumbnail': str,
|
||||
'timestamp': float,
|
||||
},
|
||||
'playlist': [{
|
||||
'info_dict': {
|
||||
'id': 'd61w8EQoZv1LDuPxDkQP2Q',
|
||||
'display_id': '42456529',
|
||||
'ext': 'mp4',
|
||||
'title': 'GettyImages-1027',
|
||||
'duration': 6.0,
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/42061563/p6bY08d2N4e4IDz-7J4_wkgsPq3-qgcx_small.jpg',
|
||||
},
|
||||
}, {
|
||||
'info_dict': {
|
||||
'id': 'VAsYDi7eiqZRbHodUA2meC',
|
||||
'display_id': '42456569',
|
||||
'ext': 'mp4',
|
||||
'title': 'GettyImages-1325598833',
|
||||
'duration': 6.083,
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/42052358/y3qrbDpn_2quWr_5XBi7yzS3UvEI__ZM_small.jpg',
|
||||
},
|
||||
}],
|
||||
'playlist_count': 2,
|
||||
}, {
|
||||
# <div class="vidyard-player-embed" data-uuid="vpCWTVHw3qrciLtVY94YkS"
|
||||
'url': 'https://www.gogoair.com/',
|
||||
'info_dict': {
|
||||
# These values come from the generic extractor and don't matter
|
||||
'id': str,
|
||||
'title': str,
|
||||
'description': str,
|
||||
'age_limit': 0,
|
||||
},
|
||||
'playlist': [{
|
||||
'info_dict': {
|
||||
'id': 'vpCWTVHw3qrciLtVY94YkS',
|
||||
'display_id': '40780699',
|
||||
'ext': 'mp4',
|
||||
'title': 'Upgrade to AVANCE 100% worth it - Jason Talley, Owner and Pilot, Testimonial',
|
||||
'description': 'md5:f609824839439a51990cef55ffc472aa',
|
||||
'duration': 70.737,
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/40780699/KzjfYZz5MZl2gHF_e-4i2c6ib1cLDweQ_small.jpg',
|
||||
},
|
||||
}, {
|
||||
'info_dict': {
|
||||
'id': 'xAmV9AsLbnitCw35paLBD8',
|
||||
'display_id': '31130867',
|
||||
'ext': 'mp4',
|
||||
'title': 'Brad Keselowski goes faster with Gogo AVANCE inflight Wi-Fi',
|
||||
'duration': 132.565,
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/31130867/HknyDtLdm2Eih9JZ4A5XLjhfBX_6HRw5_small.jpg',
|
||||
},
|
||||
}, {
|
||||
'info_dict': {
|
||||
'id': 'RkkrFRNxfP79nwCQavecpF',
|
||||
'display_id': '39009815',
|
||||
'ext': 'mp4',
|
||||
'title': 'Live Demo of Gogo Galileo',
|
||||
'description': 'md5:e2df497236f4e12c3fef8b392b5f23e0',
|
||||
'duration': 112.128,
|
||||
'thumbnail': 'https://cdn.vidyard.com/thumbnails/38144873/CWLlxfUbJ4Gh0ThbUum89IsEM4yupzMb_small.jpg',
|
||||
},
|
||||
}],
|
||||
'playlist_count': 3,
|
||||
}]
|
||||
|
||||
@classmethod
|
||||
def _extract_embed_urls(cls, url, webpage):
|
||||
# Handle protocol-less embed URLs
|
||||
for embed_url in super()._extract_embed_urls(url, webpage):
|
||||
if embed_url.startswith('//'):
|
||||
embed_url = f'https:{embed_url}'
|
||||
yield embed_url
|
||||
|
||||
# Extract inline/lightbox embeds
|
||||
for embed_element in re.findall(
|
||||
r'(<(?:img|div)[^>]* class=(["\'])(?:[^>"\']* )?vidyard-player-embed(?: [^>"\']*)?\2[^>]+>)', webpage):
|
||||
if video_id := extract_attributes(embed_element[0]).get('data-uuid'):
|
||||
yield f'https://play.vidyard.com/{video_id}'
|
||||
|
||||
for embed_id in re.findall(r'<script[^>]* id=["\']vidyard_embed_code_([\w-]+)["\']', webpage):
|
||||
yield f'https://play.vidyard.com/{embed_id}'
|
||||
|
||||
def _real_extract(self, url):
|
||||
video_id = self._match_id(url)
|
||||
video_json = self._fetch_video_json(video_id)
|
||||
|
||||
if len(video_json['chapters']) == 1:
|
||||
return self._process_video_json(video_json['chapters'][0], video_id)
|
||||
|
||||
return self.playlist_result(
|
||||
[self._process_video_json(chapter, video_id) for chapter in video_json['chapters']],
|
||||
str(video_json['playerUuid']), video_json.get('name'))
|
||||
@@ -1,6 +1,7 @@
|
||||
import base64
|
||||
import functools
|
||||
import itertools
|
||||
import json
|
||||
import re
|
||||
import urllib.parse
|
||||
|
||||
@@ -14,6 +15,7 @@ from ..utils import (
|
||||
determine_ext,
|
||||
get_element_by_class,
|
||||
int_or_none,
|
||||
join_nonempty,
|
||||
js_to_json,
|
||||
merge_dicts,
|
||||
parse_filesize,
|
||||
@@ -84,29 +86,23 @@ class VimeoBaseInfoExtractor(InfoExtractor):
|
||||
expected=True)
|
||||
return password
|
||||
|
||||
def _verify_video_password(self, url, video_id, password, token, vuid):
|
||||
if url.startswith('http://'):
|
||||
# vimeo only supports https now, but the user can give an http url
|
||||
url = url.replace('http://', 'https://')
|
||||
self._set_vimeo_cookie('vuid', vuid)
|
||||
return self._download_webpage(
|
||||
url + '/password', video_id, 'Verifying the password',
|
||||
'Wrong password', data=urlencode_postdata({
|
||||
'password': password,
|
||||
'token': token,
|
||||
}), headers={
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Referer': url,
|
||||
})
|
||||
|
||||
def _extract_xsrft_and_vuid(self, webpage):
|
||||
xsrft = self._search_regex(
|
||||
r'(?:(?P<q1>["\'])xsrft(?P=q1)\s*:|xsrft\s*[=:])\s*(?P<q>["\'])(?P<xsrft>.+?)(?P=q)',
|
||||
webpage, 'login token', group='xsrft')
|
||||
vuid = self._search_regex(
|
||||
r'["\']vuid["\']\s*:\s*(["\'])(?P<vuid>.+?)\1',
|
||||
webpage, 'vuid', group='vuid')
|
||||
return xsrft, vuid
|
||||
def _verify_video_password(self, video_id, password, token):
|
||||
url = f'https://vimeo.com/{video_id}'
|
||||
try:
|
||||
return self._download_webpage(
|
||||
f'{url}/password', video_id,
|
||||
'Submitting video password', data=json.dumps({
|
||||
'password': password,
|
||||
'token': token,
|
||||
}, separators=(',', ':')).encode(), headers={
|
||||
'Accept': '*/*',
|
||||
'Content-Type': 'application/json',
|
||||
'Referer': url,
|
||||
}, impersonate=True)
|
||||
except ExtractorError as error:
|
||||
if isinstance(error.cause, HTTPError) and error.cause.status == 418:
|
||||
raise ExtractorError('Wrong password', expected=True)
|
||||
raise
|
||||
|
||||
def _extract_vimeo_config(self, webpage, video_id, *args, **kwargs):
|
||||
vimeo_config = self._search_regex(
|
||||
@@ -745,21 +741,34 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||
raise ExtractorError('Wrong video password', expected=True)
|
||||
return checked
|
||||
|
||||
def _extract_from_api(self, video_id, unlisted_hash=None):
|
||||
token = self._download_json(
|
||||
'https://vimeo.com/_rv/jwt', video_id, headers={
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
})['token']
|
||||
api_url = 'https://api.vimeo.com/videos/' + video_id
|
||||
if unlisted_hash:
|
||||
api_url += ':' + unlisted_hash
|
||||
video = self._download_json(
|
||||
api_url, video_id, headers={
|
||||
'Authorization': 'jwt ' + token,
|
||||
def _call_videos_api(self, video_id, jwt_token, unlisted_hash=None):
|
||||
return self._download_json(
|
||||
join_nonempty(f'https://api.vimeo.com/videos/{video_id}', unlisted_hash, delim=':'),
|
||||
video_id, 'Downloading API JSON', headers={
|
||||
'Authorization': f'jwt {jwt_token}',
|
||||
'Accept': 'application/json',
|
||||
}, query={
|
||||
'fields': 'config_url,created_time,description,license,metadata.connections.comments.total,metadata.connections.likes.total,release_time,stats.plays',
|
||||
})
|
||||
|
||||
def _extract_from_api(self, video_id, unlisted_hash=None):
|
||||
viewer = self._download_json(
|
||||
'https://vimeo.com/_next/viewer', video_id, 'Downloading viewer info')
|
||||
|
||||
for retry in (False, True):
|
||||
try:
|
||||
video = self._call_videos_api(video_id, viewer['jwt'], unlisted_hash)
|
||||
except ExtractorError as e:
|
||||
if (not retry and isinstance(e.cause, HTTPError) and e.cause.status == 400
|
||||
and 'password' in traverse_obj(
|
||||
e.cause.response.read(),
|
||||
({bytes.decode}, {json.loads}, 'invalid_parameters', ..., 'field'),
|
||||
)):
|
||||
self._verify_video_password(
|
||||
video_id, self._get_video_password(), viewer['xsrft'])
|
||||
continue
|
||||
raise
|
||||
|
||||
info = self._parse_config(self._download_json(
|
||||
video['config_url'], video_id), video_id)
|
||||
get_timestamp = lambda x: parse_iso8601(video.get(x + '_time'))
|
||||
@@ -865,12 +874,6 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||
redirect_url, video_id, headers)
|
||||
return self._parse_config(config, video_id)
|
||||
|
||||
if re.search(r'<form[^>]+?id="pw_form"', webpage):
|
||||
video_password = self._get_video_password()
|
||||
token, vuid = self._extract_xsrft_and_vuid(webpage)
|
||||
webpage = self._verify_video_password(
|
||||
redirect_url, video_id, video_password, token, vuid)
|
||||
|
||||
vimeo_config = self._extract_vimeo_config(webpage, video_id, default=None)
|
||||
if vimeo_config:
|
||||
seed_status = vimeo_config.get('seed_status') or {}
|
||||
@@ -1290,9 +1293,7 @@ class VimeoReviewIE(VimeoBaseInfoExtractor):
|
||||
video_password = self._get_video_password()
|
||||
viewer = self._download_json(
|
||||
'https://vimeo.com/_rv/viewer', video_id)
|
||||
webpage = self._verify_video_password(
|
||||
'https://vimeo.com/' + video_id, video_id,
|
||||
video_password, viewer['xsrft'], viewer['vuid'])
|
||||
webpage = self._verify_video_password(video_id, video_password, viewer['xsrft'])
|
||||
clip_page_config = self._parse_json(self._search_regex(
|
||||
r'window\.vimeo\.clip_page_config\s*=\s*({.+?});',
|
||||
webpage, 'clip page config'), video_id)
|
||||
|
||||
@@ -5059,27 +5059,53 @@ class _UnsafeExtensionError(Exception):
|
||||
|
||||
# video
|
||||
*MEDIA_EXTENSIONS.video,
|
||||
'avif',
|
||||
'asx',
|
||||
'ismv',
|
||||
'm2t',
|
||||
'm2ts',
|
||||
'm2v',
|
||||
'm4s',
|
||||
'mng',
|
||||
'mp2v',
|
||||
'mp4v',
|
||||
'mpe',
|
||||
'mpeg',
|
||||
'mpeg1',
|
||||
'mpeg2',
|
||||
'mpeg4',
|
||||
'mxf',
|
||||
'ogm',
|
||||
'qt',
|
||||
'rm',
|
||||
'swf',
|
||||
'ts',
|
||||
'vob',
|
||||
'vp9',
|
||||
'wvm',
|
||||
|
||||
# audio
|
||||
*MEDIA_EXTENSIONS.audio,
|
||||
'3ga',
|
||||
'ac3',
|
||||
'adts',
|
||||
'aif',
|
||||
'au',
|
||||
'dts',
|
||||
'isma',
|
||||
'it',
|
||||
'mid',
|
||||
'mod',
|
||||
'mpga',
|
||||
'mp1',
|
||||
'mp2',
|
||||
'mp4a',
|
||||
'mpa',
|
||||
'ra',
|
||||
'shn',
|
||||
'xm',
|
||||
|
||||
# image
|
||||
*MEDIA_EXTENSIONS.thumbnails,
|
||||
'avif',
|
||||
'bmp',
|
||||
'gif',
|
||||
'heic',
|
||||
@@ -5089,6 +5115,7 @@ class _UnsafeExtensionError(Exception):
|
||||
'jxl',
|
||||
'svg',
|
||||
'tif',
|
||||
'tiff',
|
||||
'wbmp',
|
||||
|
||||
# subtitle
|
||||
@@ -5096,11 +5123,16 @@ class _UnsafeExtensionError(Exception):
|
||||
'dfxp',
|
||||
'fs',
|
||||
'ismt',
|
||||
'json3',
|
||||
'sami',
|
||||
'scc',
|
||||
'srv1',
|
||||
'srv2',
|
||||
'srv3',
|
||||
'ssa',
|
||||
'tt',
|
||||
'ttml',
|
||||
'xml',
|
||||
|
||||
# others
|
||||
*MEDIA_EXTENSIONS.manifests,
|
||||
@@ -5111,7 +5143,6 @@ class _UnsafeExtensionError(Exception):
|
||||
'sbv',
|
||||
'url',
|
||||
'webloc',
|
||||
'xml',
|
||||
])
|
||||
|
||||
def __init__(self, extension, /):
|
||||
|
||||
Reference in New Issue
Block a user