Spaces:
Paused
Paused
| /** | |
| * IPv6 Rotation Utility | |
| * | |
| * This module provides IPv6 address rotation functionality to help avoid | |
| * "Please login" errors from YouTube by sending each request from a unique | |
| * IPv6 address within a configured IPv6 block. | |
| * | |
| * Setup instructions: https://gist.github.com/unixfox/2a9dbcb23d8f69c4582f7c85a849d5cc#linux-setup | |
| */ | |
| /** | |
| * Generate a random IPv6 address within the specified IPv6 block | |
| * @param ipv6Block - The IPv6 block in CIDR notation (e.g., "2001:db8::/32") | |
| * @returns A random IPv6 address within the specified IPv6 block | |
| */ | |
| export function generateRandomIPv6(ipv6Block: string): string { | |
| // Parse the IPv6 block | |
| const [baseAddress, blockSize] = ipv6Block.split("/"); | |
| const blockBits = parseInt(blockSize, 10); | |
| if (isNaN(blockBits) || blockBits < 1 || blockBits > 128) { | |
| throw new Error("Invalid IPv6 block size"); | |
| } | |
| // Expand IPv6 address to full form | |
| const expandedBase = expandIPv6(baseAddress); | |
| // Convert to binary representation | |
| const baseBytes = ipv6ToBytes(expandedBase); | |
| // Randomize all bits after the block prefix | |
| for (let i = Math.floor(blockBits / 8); i < 16; i++) { | |
| const bitOffset = Math.max(0, blockBits - i * 8); | |
| if (bitOffset === 0) { | |
| // Fully random byte | |
| baseBytes[i] = Math.floor(Math.random() * 256); | |
| } else if (bitOffset < 8) { | |
| // Partially random byte | |
| const mask = (1 << (8 - bitOffset)) - 1; | |
| const randomPart = Math.floor(Math.random() * (mask + 1)); | |
| baseBytes[i] = (baseBytes[i] & ~mask) | randomPart; | |
| } | |
| // else: keep the original byte (bitOffset >= 8) | |
| } | |
| // Convert back to IPv6 string | |
| return bytesToIPv6(baseBytes); | |
| } | |
| /** | |
| * Expand an IPv6 address to its full form | |
| */ | |
| function expandIPv6(address: string): string { | |
| // Handle :: expansion | |
| if (address.includes("::")) { | |
| const parts = address.split("::"); | |
| const leftParts = parts[0] ? parts[0].split(":") : []; | |
| const rightParts = parts[1] ? parts[1].split(":") : []; | |
| const missingParts = 8 - leftParts.length - rightParts.length; | |
| const middle = Array(missingParts).fill("0000"); | |
| const allParts = [...leftParts, ...middle, ...rightParts]; | |
| return allParts.map((p) => p.padStart(4, "0")).join(":"); | |
| } | |
| // Pad each part to 4 characters | |
| return address.split(":").map((p) => p.padStart(4, "0")).join(":"); | |
| } | |
| /** | |
| * Convert IPv6 address string to byte array | |
| */ | |
| function ipv6ToBytes(address: string): number[] { | |
| const parts = address.split(":"); | |
| const bytes: number[] = []; | |
| for (const part of parts) { | |
| const value = parseInt(part, 16); | |
| bytes.push((value >> 8) & 0xFF); | |
| bytes.push(value & 0xFF); | |
| } | |
| return bytes; | |
| } | |
| /** | |
| * Convert byte array back to IPv6 address string | |
| */ | |
| function bytesToIPv6(bytes: number[]): string { | |
| const parts: string[] = []; | |
| for (let i = 0; i < 16; i += 2) { | |
| const value = (bytes[i] << 8) | bytes[i + 1]; | |
| parts.push(value.toString(16)); | |
| } | |
| // Compress consecutive zeros | |
| let ipv6 = parts.join(":"); | |
| // Find the longest sequence of consecutive zeros | |
| const zeroSequences = ipv6.match(/(^|:)(0:)+/g); | |
| if (zeroSequences) { | |
| const longestZeroSeq = zeroSequences.reduce((a, b) => | |
| a.length > b.length ? a : b | |
| ); | |
| ipv6 = ipv6.replace(longestZeroSeq, longestZeroSeq[0] + ":"); | |
| } | |
| return ipv6; | |
| } | |