one
Client
- Регистрация
- 22.09.2015
- Сообщения
- 7 016
- Реакции
- 1 311
- Баллы
- 113
У меня метод из старто поста уже сколько лет работает. Встявляет картинки в пост на ФБ. В конкурсах где то есть этот шаблон с этим методом.
запросто... просто посмотри какой лок используется в коде и сразу будет ясно в каких случаях он не будет работать.Хз как под локом он может пересечся. Или речь идет о пересечении при работе человека за пк?

Не врублюсь, а чем этот лок не подходит?запросто... просто посмотри какой лок используется в коде и сразу будет ясно в каких случаях он не будет работать.
не то что всегда не будет работать... но как всегда есть НО...
Видимо лок распределяется на один проект, а у людишек проекты одновременно работают с одним и тем же функционалом.Не врублюсь, а чем этот лок не подходит?
Нет, этот лок не работает на один проект.Видимо лок распределяется на один проект, а у людишек проекты одновременно работают с одним и тем же функционалом.
// Блокировка: True
// Построить путь к файлу
var lockFilePath = Path.Combine(project.Directory, "01 - The Base\01 - Cookies\The Lock.txt");
// Проверить, доступен ли буфер обмена
if (File.ReadAllText(lockFilePath) == "False")
{
// Буфер обмена доступен, записать "True", чтобы заблокировать его
File.WriteAllText(lockFilePath, "True");
}
else
{
// Подождите, пока буфер обмена не станет доступным
while (File.ReadAllText(lockFilePath) != "False")
{
// Подождите 1 секунду перед повторной попыткой
Thread.Sleep(1000);
}
// Как только буфер обмена станет доступным, записать "True", чтобы заблокировать его
File.WriteAllText(lockFilePath, "True");
}
Есть большая вероятность что при больших объемах потоков проект зациклиться и станет работать медленно, разумнее всего при итерации попыток вставки пробовать другие методы, такие как SET, либо эмуляцию клавиатуры на крайний вариантВоскресенье - время для отдыха, поэтому это Zenno:bo.
Использование буфера обмена в автоматизации следует избегать, но в некоторых случаях я использую его, потому что:
Эмуляция текста занимает слишком много времени (если установлен быстрый режим, текст не распознается/область текста не активирована). Для целей SEO, когда я не могу отправить HTML/разметку в качестве гостя. Чтобы избежать конфликтов в многопоточном использовании буфера обмена, я использую: lock(SyncObjects.InputSyncer), но это работает только во время выполнения блока C#.
Однако в некоторых случаях я выполняю операции копирования и вставки, между которыми есть несколько блоков, которые не являются пользовательскими блоками C# (и которые я не могу/не хочу преобразовывать). Поэтому на данный момент я использую простое решение: внешний файл, который действует как "блокировка" с булевым выбором, управляющим доступом к буферу обмена! Цель состоит в том, чтобы убедиться, что когда элемент копируется в буфер обмена, это не другой поток вставляет его, потому что между блоками есть задержка в несколько секунд, и может быть переплетение.
Я создал нижеуказанный код, что вы думаете об использованном методе?
Могло ли быть более простое/надежное решение?
C#:// Блокировка: True // Построить путь к файлу var lockFilePath = Path.Combine(project.Directory, "01 - The Base\01 - Cookies\The Lock.txt"); // Проверить, доступен ли буфер обмена if (File.ReadAllText(lockFilePath) == "False") { // Буфер обмена доступен, записать "True", чтобы заблокировать его File.WriteAllText(lockFilePath, "True"); } else { // Подождите, пока буфер обмена не станет доступным while (File.ReadAllText(lockFilePath) != "False") { // Подождите 1 секунду перед повторной попыткой Thread.Sleep(1000); } // Как только буфер обмена станет доступным, записать "True", чтобы заблокировать его File.WriteAllText(lockFilePath, "True"); }
Затем в конце процесса мы записываем "False" в текстовый файл.
Заранее спасибо за ваш совет!
![]()
PS :
Прошу прощения за возможные странности в моем русском тексте, я использую сервис перевода для своих сообщений. На данный момент я не владею русским языком, но с большим интересом и вниманием читаю русскую часть форума благодаря сервису перевода. Все ясно, что именно здесь, в русскоязычном сообществе, скрывается больше всего ценной информации. Так что, если я хочу продвинуться с Zenno, мне нужно отправиться на сторону русского сообщества!
На данный момент, единственное слово, которое я знаю на русском, это 'здоровье'


а буфер обмена как был один и не предназначеный для работы в многопотоке, так и осталсяДрузья, появилась новая инфа на счет вставки, но с помощью хот кеев. По сути метод прост: Устанавливаете софт который биндит хоткеи и эмулируете для каждого отдельного проекта с буфером обмена свой отдельный метод вставки. Так же возможно напрямую менять файл с вариацией вставки текста.![]()

Напитонил софт для вас, работает как с буфером так и с методом быстрой прописи текста, а так же есть настройка и пример. Не забудьте установить python с несколькими библиотеками, которые найдете в кодеДрузья, появилась новая инфа на счет вставки, но с помощью хот кеев. По сути метод прост: Устанавливаете софт который биндит хоткеи и эмулируете для каждого отдельного проекта с буфером обмена свой отдельный метод вставки. Так же возможно напрямую менять файл с вариацией вставки текста.![]()

что это меняет в глобальном смысле кроме того, что появился дополнительный костыль?Напитонил софт для вас, работает как с буфером так и с методом быстрой прописи текста, а так же есть настройка и пример. Не забудьте установить python с несколькими библиотеками, которые найдете в коде
Чтобы применить в инстансе необходима команда:
instance.ActiveTab.KeyEvent("Горячая клавиша", "press", "Клавиша с которой начинается комбинация");
Меняет то что теперь работает одна программа через которую проходит весь буфер обмена, вам теперь не нужно постоянно выполнять в каждом проекте и потоке кусок кода который отвечает за прерывание потока и установку текста в буфер. Все работает уже скомпилированным и тем является быстрым решением для многопоточного многопроектного проектища)что это меняет в глобальном смысле кроме того, что появился дополнительный костыль?
Единственный костыль с которым вы столкнетесь, это спам горячей клавиши если питон не включен.вы просто братья по несчастью, которые хотят быстрой и правильной работы от чего то одного. Так вот я предоставил вам несколько вариаций обхода неправильной логики дабы прийти к одному годному варианту.
Ах вы наши сладенькие, я вам в праве вообще не отвечатьничего не меняет... просто глянь его историю сообщений
думаю он тебе ответит примерно такхотя может преды научили общаться...
Посмотреть вложение 121190

любой код=часть природыбудто нейронка пишет
zenno.club
// Имя переменной ZennoPoster, содержимое которой нужно вставить
string variableName = "text";
try
{
// 1. Получаем текст
string text = project.Variables[variableName].Value;
if (string.IsNullOrEmpty(text))
{
project.SendWarningToLog("[VirtualClipboard] Переменная пуста. Нечего вставлять.");
return "empty";
}
if (instance.ActiveTab.IsVoid)
{
throw new System.Exception("Активная вкладка недоступна.");
}
// 2. ЖЕСТКАЯ НОРМАЛИЗАЦИЯ: Убираем конфликты Windows-переносов (\r\n) и Mac/Linux (\n)
text = text.Replace("\r\n", "\n").Replace("\r", "\n");
// 3. Кодируем в Base64 для безопасной передачи
byte[] textBytes = System.Text.Encoding.UTF8.GetBytes(text);
string base64Text = System.Convert.ToBase64String(textBytes);
// 4. Формируем усовершенствованный JS-код
string jsCode = @"
(function() {
function decodeB64Utf8(b64) {
var bin = window.atob(b64);
var bytes = new Uint8Array(bin.length);
for (var i = 0; i < bin.length; i++) {
bytes[i] = bin.charCodeAt(i);
}
return new TextDecoder('utf-8').decode(bytes);
}
var activeEl = document.activeElement;
if (!activeEl || activeEl.tagName === 'BODY') {
return 'no_focus';
}
var textToPaste = decodeB64Utf8('" + base64Text + @"');
if (activeEl.hasAttribute('maxlength')) {
activeEl.removeAttribute('maxlength');
}
// --- УРОВЕНЬ 1: Эмуляция события Ctrl+V (Paste Event) ---
// Идеально для сложных сайтов. Мы заставляем сайт думать, что произошла реальная вставка.
try {
var dataTransfer = new DataTransfer();
dataTransfer.setData('text/plain', textToPaste);
var pasteEvent = new ClipboardEvent('paste', {
clipboardData: dataTransfer,
bubbles: true,
cancelable: true
});
// Если сайт перехватил событие (вернул false), значит он сам обработал текст
var handledBySite = !activeEl.dispatchEvent(pasteEvent);
if (handledBySite) {
activeEl.dispatchEvent(new Event('input', { bubbles: true }));
activeEl.dispatchEvent(new Event('change', { bubbles: true }));
return 'ok';
}
} catch (e) {
// Игнорируем ошибку, переходим к следующему методу
}
var success = false;
// --- УРОВЕНЬ 2: Нативная команда браузера ---
try {
success = document.execCommand('insertText', false, textToPaste);
} catch(e) {
success = false;
}
// --- УРОВЕНЬ 3: Глубокий Fallback ---
// Проверяем, вставился ли текст. Если нет — вставляем вручную с учетом структуры.
if (!success || (activeEl.value !== undefined && activeEl.value.indexOf(textToPaste) === -1)) {
// Для классических <input> и <textarea>
if (activeEl.tagName === 'INPUT' || activeEl.tagName === 'TEXTAREA') {
var start = activeEl.selectionStart;
var end = activeEl.selectionEnd;
var val = activeEl.value;
activeEl.value = val.substring(0, start) + textToPaste + val.substring(end);
activeEl.selectionStart = activeEl.selectionEnd = start + textToPaste.length;
success = true;
}
// Для сложных редакторов (contenteditable)
else if (activeEl.isContentEditable) {
var sel = window.getSelection();
if (sel.rangeCount > 0) {
var range = sel.getRangeAt(0);
range.deleteContents();
// Разбиваем текст по строкам и создаем правильную HTML-структуру с тегами <br>
var lines = textToPaste.split('\n');
var frag = document.createDocumentFragment();
for (var i = 0; i < lines.length; i++) {
frag.appendChild(document.createTextNode(lines[i]));
// Добавляем перенос строки, если это не последняя строка
if (i < lines.length - 1) {
frag.appendChild(document.createElement('br'));
}
}
range.insertNode(frag);
range.collapse(false); // Сдвигаем курсор в конец
success = true;
} else {
activeEl.innerText += textToPaste;
success = true;
}
}
}
// Триггерим события изменения для активации кнопок 'Отправить'
if (success) {
activeEl.dispatchEvent(new Event('input', { bubbles: true }));
activeEl.dispatchEvent(new Event('change', { bubbles: true }));
}
return success ? 'ok' : 'fail';
})();
";
// 5. Выполняем скрипт
string result = instance.ActiveTab.MainDocument.EvaluateScript(jsCode);
// 6. Обработка результатов
if (result == "no_focus")
{
throw new System.Exception("Ни один элемент на странице не находится в фокусе.");
}
if (result == "fail")
{
throw new System.Exception("Браузер отклонил вставку текста всеми 3 методами.");
}
project.SendInfoToLog("[VirtualClipboard] Мультистрочный текст успешно вставлен.");
return "ok";
}
catch (System.Threading.ThreadAbortException)
{
project.SendWarningToLog("[VirtualClipboard] Выполнение прервано пользователем.");
return "aborted";
}
catch (System.Exception ex)
{
project.SendErrorToLog("[VirtualClipboard] Ошибка: " + ex.Message);
return "error";
}
А чем это профессиональное решение отличается кардинально например от вот этого?Существует профессиональное и полностью изолированное решение. Создание виртуального буфера обмена с помощью нативного JavaScript API.
Скрипт ниже берет значение из переменной ZennoPoster и применяет браузерную команду insertText к активному (выделенному) элементу. Для сайта (включая сложные фреймворки вроде React или Vue) это выглядит в точности как вставка из буфера обмена единым блоком. При этом:
- Системный буфер обмена Windows вообще не используется.
- Потоки работают на 100% независимо и никогда не пересекаются.
- Корректно срабатывают все события input и change на сайте.
C#:// Имя переменной ZennoPoster, содержимое которой нужно "вставить" string variableName = "text_to_paste"; try { // 1. Получаем текст string text = project.Variables[variableName].Value; if (string.IsNullOrEmpty(text)) { project.SendWarningToLog("[VirtualClipboard] Переменная пуста. Нечего вставлять."); return "empty"; } if (instance.ActiveTab.IsVoid) { throw new System.Exception("Активная вкладка недоступна."); } // 2. Безопасное экранирование текста для передачи в JavaScript // Это гарантирует, что переносы строк, кавычки и слэши не сломают JS-код string escapedText = text.Replace("\\", "\\\\") .Replace("\"", "\\\"") .Replace("\r", "") .Replace("\n", "\\n"); // 3. Формируем JS-код виртуальной вставки // Используем конкатенацию вместо string.Format, чтобы избежать ошибки с { и } string jsCode = @" (function() { var textToPaste = """ + escapedText + @"""; var activeEl = document.activeElement; // Проверяем, установлен ли фокус на какой-либо элемент ввода if (!activeEl || activeEl.tagName === 'BODY') { return 'no_focus'; } // Основной метод: Нативная команда браузера. // Вставляет текст единым куском (как Ctrl+V), не затрагивая буфер ОС // и сохраняя возможность отмены (Undo/Ctrl+Z) в браузере. var success = document.execCommand('insertText', false, textToPaste); // Fallback-метод: Если сайт блокирует execCommand, симулируем вставку вручную if (!success) { var start = activeEl.selectionStart; var end = activeEl.selectionEnd; // Если это стандартное поле input или textarea if (typeof start === 'number') { var val = activeEl.value; activeEl.value = val.slice(0, start) + textToPaste + val.slice(end); activeEl.selectionStart = activeEl.selectionEnd = start + textToPaste.length; // Триггерим события для активации React/Vue обработчиков activeEl.dispatchEvent(new Event('input', { bubbles: true })); activeEl.dispatchEvent(new Event('change', { bubbles: true })); success = true; } // Если это contenteditable элемент (например, WhatsApp Web, WYSIWYG редакторы) else if (activeEl.isContentEditable) { activeEl.innerText += textToPaste; activeEl.dispatchEvent(new Event('input', { bubbles: true })); success = true; } } return success ? 'ok' : 'fail'; })(); "; // 4. Выполняем скрипт внутри контекста браузера текущего потока string result = instance.ActiveTab.MainDocument.EvaluateScript(jsCode); // 5. Обработка результатов if (result == "no_focus") { throw new System.Exception("Ни один элемент на странице не находится в фокусе. Перед вставкой необходимо кликнуть в нужное поле."); } if (result == "fail") { throw new System.Exception("Браузер отклонил виртуальную вставку. Возможно, активный элемент не поддерживает текстовый ввод."); } project.SendInfoToLog("[VirtualClipboard] Текст успешно вставлен (Изолированно от ОС)."); return "ok"; } catch (System.Threading.ThreadAbortException) { project.SendWarningToLog("[VirtualClipboard] Выполнение прервано пользователем."); return "aborted"; } catch (System.Exception ex) { project.SendErrorToLog("[VirtualClipboard] Критическая ошибка: " + ex.Message); return "error"; }
Оба скрипта решают одну глобальную задачу — изоляцию потоков от системного буфера обмена ОС Windows.Но первый скрипт нужен для безопасного ЧТЕНИЯ с сайта (копирование), а второй — для безопасной ЗАПИСИ на сайт (вставка). Используя их вместе, вы получаете полностью замкнутый и независимый буфер обмена внутри конкретного потока браузера.А чем это профессиональное решение отличается кардинально например от вот этого?


