Гобелен - кликните для возврата на главную
Не прошло и месяца а Фурмановская ЦРБ в очередной раз попала в историю. На этот раз сотрудница клеветала на пациентов, а именно огласку получил случай когда сотрудница назвала пациента алкашём.
Так почему бы не начать использовать обход блокировки YouTube при том что техническая возможность используя расширение nikolaevevge для браузера Mozilla Firefox уже появилась, а объем полезной(и не очень) информации на видеохостинге YouTube, по мнению некоторых диванных экспертов, меньше не стал.
Ровно 3 года назад произошло событие, которое подарило жителям планеты Змеля новый чистый праздник 6 апреля - в этот замечательный день земля забрала гнить негодяя и СПАМера Владимира Вольфовича Жириновского.
Как бы не обстояли дела в области культуры и IT-технологий, Самосвал писал статьи на связанные темы и планирует ещё написать.
На очередном конкурсе танцев, школьница отлично выступила.
Вот та самая информация: программа для продвижения канала YouTube, эта информация выложена уже несколько лет, при этом просмотров не много, а метод который описан в данном видео действительно помогает продвигать видео в YouTube.
Начал разбираться с информацией которая находится в HTTPS клиентском запросе рукопожатия.
Обратите внимание! Объект изображённый на гобилене может отличаться от общепринятого вида описанного объекта. Тут дело в том что художник видит именно так!
И ещё несколько доработок. Теперь ответ от сервера будет выглядеть следующим образом: {"server":{"en":{"ip":"46.17.107.238","port":1088},"ru":{"ip":"80.87.202.236","port":1088}},"plginfo":"
\u0421\u0435\u0439\u0447\u0430\u0441 \u0442\u0443\u0442 \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u0432\u043e\u0442 \u0442\u0430\u043a\u0430\u044f \u0432\u043e\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0438 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 <a href=\"https:\/\/vk.com\/nikolaevevge\">\u043c\u043e\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0412\u041a\u043e\u043d\u0442\u0430\u043a\u0442\u0435<\/a>.<\/p>","update":2}
Таким образом список прокси серверов теперь в server. Так же добавлено свойство plginfo которая содержит HTML. Его требуется вывести в специальный div между статусом и версией. Так же добавлено свойство update которое может возвращать следующие значения: 0, 1 и 2. При 0 - обновлять плагин не требуется, так же при этом значении никакая информация в popup не выводится. При 1 в статусе появляется статус "Доступно обновление"(цвет поля синего оттенка), при 2 - обновление обязательно и с текущей версией плагин работать не будет, при этом значении отображается статус - "Требуется обновление"(цвет поля красного оттенка). Важно - указанные статусы выводятся именно там же где статус например ошибки, поэтому определимся с приоритетами. Статус "Ошибка" - приоритетнее чем "Доступно обновление", "Доступно обновление" и "Требуется обновление" приоритетнее чем "Готовность", "Требуется обновление" приоритетнее чем "Ошибка", "Инициализация" - приоритетнее всех выше указанных, то-есть не зависимо от статуса обращения к серверу продолжают направляться каждые 5 минут(как это реализовано сейчас) и далее устанавливаются те настройки и статусы которые вновь прислал сервер. Ещё информация от сервера может вернуть свойство updatehref, его наличие проверяется если update имеет значение 1 или 2, при них тем не менее updatehref может отсутствовать. Если он присутствует текст статуса становится ссылкой открываемой в новом окне, а href этой ссылки берётся из updatehref.
Вот полные коды всех изменённых файлов с реализацией новых требований:
Файл background.js
const DEFAULT_SETTINGS = {
masterSwitch: true,
googlevideo: true,
youtube: true,
ytimg: true,
ggpht: true
};
// Константы для идентификации
const PROJ_KEY = "Df730xxC41XpN4YbREho";
const VERSION = "1.0.0a";
let currentSettings = {...DEFAULT_SETTINGS};
let proxyListener = null;
let PROXY = null;
let PROXY2 = null;
let proxyStatus = "initializing";
let serverData = {
plginfo: "",
update: 0,
updatehref: ""
};
// Генерация UUID
function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
// Инициализация идентификаторов
async function initIds() {
let { persistentId } = await browser.storage.local.get('persistentId');
if (!persistentId) {
persistentId = generateUUID();
await browser.storage.local.set({ persistentId });
}
const sessionId = generateUUID();
await browser.storage.local.set({ sessionId });
console.log('Идентификаторы инициализированы:', { persistentId, sessionId });
return { persistentId, sessionId };
}
// Инициализация при запуске браузера
browser.runtime.onStartup.addListener(async () => {
await initIds();
browser.storage.local.set(DEFAULT_SETTINGS);
setupProxy();
});
// Инициализация при установке
browser.runtime.onInstalled.addListener(async () => {
await initIds();
browser.storage.local.set(DEFAULT_SETTINGS);
setupProxy();
});
async function fetchProxies() {
try {
proxyStatus = "initializing";
sendStatusUpdate();
const { persistentId, sessionId } = await browser.storage.local.get(['persistentId', 'sessionId']);
const formData = new FormData();
formData.append('projKey', PROJ_KEY);
formData.append('version', VERSION);
formData.append('persistentId', persistentId);
formData.append('sessionId', sessionId);
const response = await fetch('https://10-11/getProxDataBeta.php', {
method: 'POST',
body: formData
});
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const data = await response.json();
console.log("Received server data:", data);
if (!data.server || !data.server.en || !data.server.ru) {
throw new Error("Invalid server data format");
}
// Сохраняем данные с сервера
serverData = {
plginfo: data.plginfo || "",
update: data.update || 0,
updatehref: data.updatehref || ""
};
PROXY = {
host: data.server.en.ip,
port: data.server.en.port
};
PROXY2 = {
host: data.server.ru.ip,
port: data.server.ru.port
};
// Определяем статус с учетом приоритетов
if (data.update === 2) {
proxyStatus = "update-required";
} else if (data.update === 1) {
proxyStatus = "update-available";
} else {
proxyStatus = "ready";
}
console.log('Прокси и данные успешно получены:', { PROXY, PROXY2, serverData });
} catch (error) {
console.error('Ошибка при получении данных:', error);
// При ошибке сохраняем только статус ошибки, остальные данные не трогаем
proxyStatus = "error";
} finally {
sendStatusUpdate();
}
}
function sendStatusUpdate() {
browser.runtime.sendMessage({
type: "statusUpdate",
status: proxyStatus,
version: VERSION,
serverData: serverData
}).catch(e => console.log("Не удалось отправить статус:", e));
}
// Обработчик запросов из popup
browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.type === "getStatus") {
sendResponse({
status: proxyStatus,
version: VERSION,
serverData: serverData
});
}
});
// Остальные функции (getSettings, handleProxyRequest, setupProxy) остаются без изменений
Файл popup.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: #000;
display: flex;
justify-content: center;
align-items: center;
min-height: 200px;
width: 200px;
margin: 0;
font-family: Arial, sans-serif;
color: white;
padding: 10px;
box-sizing: border-box;
}
.container {
width: 100%;
}
/* ... [остальные стили без изменений] ... */
.status {
text-align: center;
margin-top: 10px;
padding: 5px;
border-radius: 3px;
font-size: 12px;
}
.status-initializing {
background-color: #FFC107;
color: black;
}
.status-ready {
background-color: #4CAF50;
}
.status-error {
background-color: #F44336;
}
.status-update-available {
background-color: #2196F3;
}
.status-update-required {
background-color: #F44336;
font-weight: bold;
}
.plugin-info {
margin: 10px 0;
padding: 5px;
font-size: 11px;
line-height: 1.3;
color: #ccc;
}
.plugin-info a {
color: #4CAF50;
text-decoration: none;
}
.plugin-info a:hover {
text-decoration: underline;
}
.version {
text-align: center;
margin-top: 5px;
font-size: 11px;
color: #888;
}
</style>
</head>
<body>
<div class="container">
<!-- ... [остальная разметка без изменений] ... -->
<div id="status" class="status status-initializing">Инициализация</div>
<div id="plugin-info" class="plugin-info"></div>
<div id="version" class="version">v. 1.0.0a</div>
</div>
<script src="popup.js"></script>
</body>
</html>
Файл popup.js
async function loadSettings() {
const result = await browser.storage.local.get({
masterSwitch: true,
googlevideo: true,
youtube: true,
ytimg: true,
ggpht: true
});
// ... [настройка переключателей без изменений] ...
// Получаем текущий статус и данные
try {
const response = await browser.runtime.sendMessage({type: "getStatus"});
updateStatus(response.status, response.serverData);
document.getElementById('version').textContent = `v. ${response.version}`;
updatePluginInfo(response.serverData);
} catch (e) {
console.error("Ошибка при получении данных:", e);
updateStatus("error");
}
// Слушаем обновления
browser.runtime.onMessage.addListener((message) => {
if (message.type === "statusUpdate") {
updateStatus(message.status, message.serverData);
updatePluginInfo(message.serverData);
}
});
}
function updateStatus(status, serverData = {}) {
const statusElement = document.getElementById('status');
statusElement.className = 'status';
statusElement.innerHTML = ''; // Очищаем содержимое
// Приоритеты статусов
const statusTexts = {
"initializing": "Инициализация",
"error": "Ошибка",
"update-required": serverData.updatehref
? `<a href="${serverData.updatehref}" target="_blank">Требуется обновление</a>`
: "Требуется обновление",
"update-available": serverData.updatehref
? `<a href="${serverData.updatehref}" target="_blank">Доступно обновление</a>`
: "Доступно обновление",
"ready": "Готов к работе"
};
// Устанавливаем соответствующий класс и текст
statusElement.classList.add(`status-${status}`);
statusElement.innerHTML = statusTexts[status] || status;
}
function updatePluginInfo(serverData) {
const infoElement = document.getElementById('plugin-info');
// Показываем информацию только если update = 0 и есть plginfo
if (serverData.update === 0 && serverData.plginfo) {
infoElement.innerHTML = serverData.plginfo;
infoElement.style.display = 'block';
} else {
infoElement.innerHTML = '';
infoElement.style.display = 'none';
}
}
// ... [остальные функции без изменений] ...
Основные изменения:
Добавлена обработка нового формата ответа сервера
Реализована система приоритетов статусов
Добавлены новые статусы обновлений с разными цветами
Реализовано отображение HTML-информации от сервера
Добавлена поддержка ссылок в статусах обновлений
Обновлены стили для новых элементов
Приоритеты статусов:
Инициализация (жёлтый) - самый высокий приоритет
Требуется обновление (красный)
Ошибка (красный)
Доступно обновление (синий)
Готов к работе (зелёный) - самый низкий приоритет
Информация от сервера (plginfo) отображается только когда update = 0. При статусах обновления (1 или 2) информация скрывается.
Верните пожалуйста полный код изменённых файлов без фраз вроде "[остальные функции без изменений]".
Вот полные коды всех изменённых файлов с реализацией новых требований:
Файл background.js
const DEFAULT_SETTINGS = {
masterSwitch: true,
googlevideo: true,
youtube: true,
ytimg: true,
ggpht: true
};
const PROJ_KEY = "Df730xxC41XpN4YbREho";
const VERSION = "1.0.0a";
let currentSettings = {...DEFAULT_SETTINGS};
let proxyListener = null;
let PROXY = null;
let PROXY2 = null;
let proxyStatus = "initializing";
let serverData = {
plginfo: "",
update: 0,
updatehref: ""
};
function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
async function initIds() {
let { persistentId } = await browser.storage.local.get('persistentId');
if (!persistentId) {
persistentId = generateUUID();
await browser.storage.local.set({ persistentId });
}
const sessionId = generateUUID();
await browser.storage.local.set({ sessionId });
console.log('Идентификаторы инициализированы:', { persistentId, sessionId });
return { persistentId, sessionId };
}
browser.runtime.onStartup.addListener(async () => {
await initIds();
browser.storage.local.set(DEFAULT_SETTINGS);
setupProxy();
});
browser.runtime.onInstalled.addListener(async () => {
await initIds();
browser.storage.local.set(DEFAULT_SETTINGS);
setupProxy();
});
async function fetchProxies() {
try {
proxyStatus = "initializing";
sendStatusUpdate();
const { persistentId, sessionId } = await browser.storage.local.get(['persistentId', 'sessionId']);
const formData = new FormData();
formData.append('projKey', PROJ_KEY);
formData.append('version', VERSION);
formData.append('persistentId', persistentId);
formData.append('sessionId', sessionId);
const response = await fetch('https://10-11/getProxDataBeta.php', {
method: 'POST',
body: formData
});
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const data = await response.json();
console.log("Received server data:", data);
if (!data.server || !data.server.en || !data.server.ru) {
throw new Error("Invalid server data format");
}
serverData = {
plginfo: data.plginfo || "",
update: data.update || 0,
updatehref: data.updatehref || ""
};
PROXY = {
host: data.server.en.ip,
port: data.server.en.port
};
PROXY2 = {
host: data.server.ru.ip,
port: data.server.ru.port
};
if (data.update === 2) {
proxyStatus = "update-required";
} else if (data.update === 1) {
proxyStatus = "update-available";
} else {
proxyStatus = "ready";
}
console.log('Прокси и данные успешно получены:', { PROXY, PROXY2, serverData });
} catch (error) {
console.error('Ошибка при получении данных:', error);
proxyStatus = "error";
} finally {
sendStatusUpdate();
}
}
function sendStatusUpdate() {
browser.runtime.sendMessage({
type: "statusUpdate",
status: proxyStatus,
version: VERSION,
serverData: serverData
}).catch(e => console.log("Не удалось отправить статус:", e));
}
browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.type === "getStatus") {
sendResponse({
status: proxyStatus,
version: VERSION,
serverData: serverData
});
}
});
async function getSettings() {
const settings = await browser.storage.local.get(DEFAULT_SETTINGS);
currentSettings = {...DEFAULT_SETTINGS, ...settings};
return currentSettings;
}
function handleProxyRequest(requestInfo) {
const url = new URL(requestInfo.url);
const hostname = url.hostname;
if (!currentSettings.masterSwitch || proxyStatus !== "ready" || !PROXY || !PROXY2) {
return { type: "direct" };
}
if (hostname.endsWith('instagram.com') ||
hostname.endsWith('fbcdn.net') ||
hostname.endsWith('chatgpt.com') ||
hostname.endsWith('fb.com') ||
hostname.endsWith('facebook.com') ||
hostname.endsWith('ionos.com')) {
console.log(`Проксируем (PROXY) запрос к: ${hostname}`);
return {
type: "socks",
host: PROXY.host,
port: PROXY.port,
proxyDNS: true,
failoverTimeout: 5
};
}
if ((hostname.endsWith('googlevideo.com') && currentSettings.googlevideo) ||
(hostname.endsWith('youtube.com') && currentSettings.youtube) ||
(hostname.endsWith('ytimg.com') && currentSettings.ytimg) ||
(hostname.endsWith('ggpht.com') && currentSettings.ggpht)) {
console.log(`Проксируем (PROXY2) запрос к: ${hostname}`);
return {
type: "socks",
host: PROXY2.host,
port: PROXY2.port,
proxyDNS: true,
failoverTimeout: 5
};
}
return { type: "direct" };
}
async function setupProxy() {
if (proxyListener) {
browser.proxy.onRequest.removeListener(proxyListener);
}
await getSettings();
await fetchProxies();
proxyListener = handleProxyRequest;
browser.proxy.onRequest.addListener(
proxyListener,
{ urls: ["*://*.googlevideo.com/*", "*://googlevideo.com/*",
"*://*.instagram.com/*", "*://instagram.com/*",
"*://*.fbcdn.net/*", "*://fbcdn.net/*",
"*://*.facebook.com/*", "*://facebook.com/*",
"*://*.fb.com/*", "*://fb.com/*",
"*://*.youtube.com/*", "*://youtube.com/*",
"*://*.chatgpt.com/*", "*://chatgpt.com/*",
"*://*.ionos.com/*", "*://ionos.com/*",
"*://*.ytimg.com/*", "*://ytimg.com/*",
"*://*.ggpht.com/*", "*://ggpht.com/*"] }
);
console.log("Прокси обновлено с новыми настройками", currentSettings);
}
setInterval(fetchProxies, 5 * 60 * 1000);
setupProxy();
Файл popup.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: #000;
display: flex;
justify-content: center;
align-items: center;
min-height: 200px;
width: 200px;
margin: 0;
font-family: Arial, sans-serif;
color: white;
padding: 10px;
box-sizing: border-box;
}
.container {
width: 100%;
}
.header {
text-align: center;
margin-bottom: 15px;
font-weight: bold;
}
.switch-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.switch-label {
font-size: 14px;
}
.checkbox-container {
width: 24px;
height: 24px;
border: 2px solid white;
position: relative;
box-sizing: border-box;
}
.switch-track {
position: absolute;
width: 4px;
height: calc(100% - 8px);
top: 4px;
background-color: #ff0000;
transition: all 0.2s ease;
}
.switch-track {
left: 4px;
}
input:checked ~ .checkbox-container .switch-track {
right: 4px;
left: auto;
background-color: #00ff00;
}
input[type="checkbox"] {
display: none;
}
label {
display: block;
cursor: pointer;
}
.divider {
height: 1px;
background-color: #333;
margin: 10px 0;
}
.status {
text-align: center;
margin-top: 10px;
padding: 5px;
border-radius: 3px;
font-size: 12px;
}
.status-initializing {
background-color: #FFC107;
color: black;
}
.status-ready {
background-color: #4CAF50;
}
.status-error {
background-color: #F44336;
}
.status-update-available {
background-color: #2196F3;
}
.status-update-required {
background-color: #F44336;
font-weight: bold;
}
.plugin-info {
margin: 10px 0;
padding: 5px;
font-size: 11px;
line-height: 1.3;
color: #ccc;
}
.plugin-info a {
color: #4CAF50;
text-decoration: none;
}
.plugin-info a:hover {
text-decoration: underline;
}
.version {
text-align: center;
margin-top: 5px;
font-size: 11px;
color: #888;
}
.status a {
color: white;
text-decoration: none;
}
.status a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<div class="header">Proxy Control</div>
<div class="switch-row">
<span class="switch-label">Master Switch</span>
<label>
<input type="checkbox" id="master-switch" checked>
<div class="checkbox-container">
<div class="switch-track"></div>
</div>
</label>
</div>
<div class="divider"></div>
<div class="switch-row">
<span class="switch-label">googlevideo.com</span>
<label>
<input type="checkbox" id="googlevideo-switch" checked>
<div class="checkbox-container">
<div class="switch-track"></div>
</div>
</label>
</div>
<div class="switch-row">
<span class="switch-label">youtube.com</span>
<label>
<input type="checkbox" id="youtube-switch" checked>
<div class="checkbox-container">
<div class="switch-track"></div>
</div>
</label>
</div>
<div class="switch-row">
<span class="switch-label">ytimg.com</span>
<label>
<input type="checkbox" id="ytimg-switch" checked>
<div class="checkbox-container">
<div class="switch-track"></div>
</div>
</label>
</div>
<div class="switch-row">
<span class="switch-label">ggpht.com</span>
<label>
<input type="checkbox" id="ggpht-switch" checked>
<div class="checkbox-container">
<div class="switch-track"></div>
</div>
</label>
</div>
<div id="status" class="status status-initializing">Инициализация</div>
<div id="plugin-info" class="plugin-info"></div>
<div id="version" class="version">v. 1.0.0a</div>
</div>
<script src="popup.js"></script>
</body>
</html>
Файл popup.js
async function loadSettings() {
const result = await browser.storage.local.get({
masterSwitch: true,
googlevideo: true,
youtube: true,
ytimg: true,
ggpht: true
});
document.getElementById('master-switch').checked = result.masterSwitch;
document.getElementById('googlevideo-switch').checked = result.googlevideo;
document.getElementById('youtube-switch').checked = result.youtube;
document.getElementById('ytimg-switch').checked = result.ytimg;
document.getElementById('ggpht-switch').checked = result.ggpht;
try {
const response = await browser.runtime.sendMessage({type: "getStatus"});
updateStatus(response.status, response.serverData);
document.getElementById('version').textContent = `v. ${response.version}`;
updatePluginInfo(response.serverData);
} catch (e) {
console.error("Ошибка при получении данных:", e);
updateStatus("error");
}
browser.runtime.onMessage.addListener((message) => {
if (message.type === "statusUpdate") {
updateStatus(message.status, message.serverData);
updatePluginInfo(message.serverData);
}
});
}
function updateStatus(status, serverData = {}) {
const statusElement = document.getElementById('status');
statusElement.className = 'status';
statusElement.innerHTML = '';
const statusTexts = {
"initializing": "Инициализация",
"error": "Ошибка",
"update-required": serverData.updatehref
? `<a href="${serverData.updatehref}" target="_blank">Требуется обновление</a>`
: "Требуется обновление",
"update-available": serverData.updatehref
? `<a href="${serverData.updatehref}" target="_blank">Доступно обновление</a>`
: "Доступно обновление",
"ready": "Готов к работе"
};
statusElement.classList.add(`status-${status}`);
statusElement.innerHTML = statusTexts[status] || status;
}
function updatePluginInfo(serverData) {
const infoElement = document.getElementById('plugin-info');
if (serverData.update === 0 && serverData.plginfo) {
infoElement.innerHTML = serverData.plginfo;
infoElement.style.display = 'block';
} else {
infoElement.innerHTML = '';
infoElement.style.display = 'none';
}
}
async function saveSettings() {
const settings = {
masterSwitch: document.getElementById('master-switch').checked,
googlevideo: document.getElementById('googlevideo-switch').checked,
youtube: document.getElementById('youtube-switch').checked,
ytimg: document.getElementById('ytimg-switch').checked,
ggpht: document.getElementById('ggpht-switch').checked
};
await browser.storage.local.set(settings);
console.log("Настройки сохранены", settings);
}
document.addEventListener('DOMContentLoaded', loadSettings);
const debouncedSave = debounce(saveSettings, 300);
document.getElementById('master-switch').addEventListener('change', debouncedSave);
document.getElementById('googlevideo-switch').addEventListener('change', debouncedSave);
document.getElementById('youtube-switch').addEventListener('change', debouncedSave);
document.getElementById('ytimg-switch').addEventListener('change', debouncedSave);
document.getElementById('ggpht-switch').addEventListener('change', debouncedSave);
function debounce(func, wait) {
let timeout;
return function() {
const context = this, args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args);
}, wait);
};
}
Все файлы полностью приведены с реализацией:
Нового формата ответа сервера
Отображения HTML-информации
Системы статусов обновления
Ссылок в статусах обновления
Приоритетов статусов
Сохранения всех предыдущих функций
Вы так же можете прочитать следующие статьи: