Чтение сообщений Twitch Whisper с помощью Greasemonkey

У меня есть скрипт Greasemonkey, который настраивает некоторые элементы Twitch.tv в соответствии с шепотом сообщений от чат-бота на определенном канале twitch. Моя цель — наблюдать за шепотом, читать каждое новое сообщение шепота, вносить соответствующие коррективы и после этого закрывать окно чата, чтобы я не видел, что получил шепот.

Я не так хорошо знаком с Greasemonkey, HMTL или Javascript в целом. Единственный известный мне способ сделать это — использовать observeDOM в классе, содержащем все окна шепота (conversation-manager):

  // Observe twitch whisper chat
  var whisperArea = document.getElementsByClassName('conversations-manager')[0];
  observeDOM( whisperArea ,function(){ 
    NewWhisperMessage();
  });

Насколько я могу судить, наблюдение работает надежно. Теперь о том, чего нет: сам мой метод NewWhisperMessage.

Прежде всего я хочу описать свой первый подход. Вначале я пытался найти все новые шепотки. Когда получен шепот, окно шепота открывается. В самом окне шепота есть несколько строк сообщений, построенных следующим образом:

<div class="ember-view conversation-chat-line incoming" title="Sat Jul 09 2016 11:52:38 GMT+0200" id="ember2564">
<span style="" class="from">NameOfMessageWriter</span>
<span class="colon">:</span>
<span style="" class="message">
        Here is the message!
      </span>
</div>

Как правило, в этот момент я бы просто взял последний элемент класса conversation-chat-line по

var allChatMessages = document.getElementsByClassName("conversation-chat-line");
var newestChatMessage = allChatMessages[allChatMessages.length - 1];

Иногда это работает, но ненадежно, поскольку кажется, что иногда в одно обновление DOM поступает несколько сообщений (имеет ли это смысл?). Когда я это заметил, мне пришла в голову более сложная идея, которая работает более надежно, но все же довольно часто дает сбои.

Мой подход работает примерно в 4 этапа:

1) Если это первый новый шепот в этом сеансе (LastWhisperTitle все еще пусто), то необходимо найти отправную точку. Для этого я пытаюсь найти элемент-разделитель в окне twitch-чата для новых шепотных сообщений (класса new-message-divider. Оттуда я пытаюсь получить сообщение чата прямо перед этим и сохранить атрибут title и текст сообщения этого сообщения в уникально идентифицировать сообщение (я не могу использовать атрибут id, так как он меняется, когда окно шепота закрывается и снова открывается) Этот шаг выполняется только один раз.

2) Теперь я перебираю все сообщения чата в обратном порядке, пока не доберусь до последнего, идентифицированного двумя переменными (заголовок и текст сообщения). Чтобы получить все сообщения чата, я использую getElementsByClassName. Я сохраняю индекс этого самого нового сообщения и начинаю с шага 3).

3) Имея индекс первого нового сообщения чата, я начинаю перебирать вперед и анализировать каждое сообщение по порядку.

4) Закрыть окно шепота, когда будет прочитано новое сообщение. (Условие просто позволяет открыть окно шепота вручную, когда не поступило новое сообщение)

И вот последний метод:

var LastWhisperTitle = "";
var LastWhisperMessage = "";
var ChannelName = "NameOfChatBot"

function NewWhisperMessage(){

    if(LastWhisperTitle == "") {
        // New Session: Find first new whisper

        // Find new message divider
        var newMessageDividerArray = document.getElementsByClassName("new-message-divider");
        var newMessageDivider = newMessageDividerArray[newMessageDividerArray.length - 1];

        // Find newest message already read
        var sibling = newMessageDivider.previousSibling;
        while(sibling) {
            if(sibling.nodeType == 1) {
                if(sibling.className != "undefined"){
                    if(sibling.className.indexOf("conversation-chat-line") > -1) {
                        break;
                    }
                }
            }
            sibling = sibling.previousSibling;
        }
        if(!sibling){
            return;
        }

        // Store this message as last read whisper
        LastWhisperTitle = sibling.title;
        LastWhisperMessage = sibling.getElementsByClassName("message")[0].textContent.trim();
    }

    // Get all messages
    var whisperMessageArray = document.getElementsByClassName("conversation-chat-line");
    var foundNewMessage = false;

    // Find index in array of the first new message
    var firstNewMessageIndex = 0;
    for(i = whisperMessageArray.length - 1; i >= 0; i--){
        var currentWhisper = whisperMessageArray[i];
        var currentTitle = currentWhisper.title;
        var currentMessage = currentWhisper.getElementsByClassName("message")[0].textContent.trim()

        if(currentTitle == LastWhisperTitle && currentMessage == LastWhisperMessage){
            // This message was already read -> the message with the previous index is new
            if(i == whisperMessageArray.length - 1) {
                // No new message
                return;
            } else {
                firstNewMessageIndex = i+1;
                break;
            }
        }
    }   

    if(firstNewMessageIndex == 0){
        // No new message
        return;
    }

    // Parse all messages from index to newest message
    for( i = firstNewMessageIndex; i < whisperMessageArray.length; i++){
        var currentWhisper = whisperMessageArray[i];
        var writer = currentWhisper.getElementsByClassName("from")[0].textContent;
        var message = currentWhisper.getElementsByClassName("message")[0].textContent.trim();

        if(writer == ChannelName){
            ParseWhisperMessage(message);
            foundNewMessage = true;
        }
        LastWhisperTitle = currentWhisper.title;
        LastWhisperMessage = message;
    }

    if(foundNewMessage){
        // Close Chat Window
        CloseWhisperWindow();
    }

}

У меня все еще есть проблемы, что читаются только некоторые сообщения шепотом или вообще не читаются. В чем может быть проблема с моим подходом?


person Mthenn    schedule 13.07.2016    source источник
comment
Без живого примера сложно сказать. Можете ли вы рассказать нам, как открыть этот чат на твиче?   -  person wOxxOm    schedule 13.07.2016
comment
У нас было много проблем с внесением изменений в шепот в BetterTTV из-за того, как Twitch реализовал это в ember. Я не совсем уверен, что вы пытаетесь здесь сделать, но если это требует изменения шепота в DOM, вы не будете хорошо проводить время. Мы обнаружили, что даже небольшие изменения разрушают все это.   -  person Teak    schedule 14.07.2016


Ответы (1)


Кажется, я нашел проблему. Сам мой метод в основном работает, единственная проблема заключается в том, что при открытии нескольких шепотных разговоров все становится глючным, так как я использую document.getElementsByClassName("conversation-chat-line"); для всего document, который также будет принимать сообщения из разговоров от других пользователей (не только twitch бота). Это искажает значения LastWhisperTitle и LastWhisperMessage.

Решение состоит в том, чтобы поместить этот код в начало моей функции:

var conversationHeaderNames = document.getElementsByClassName('conversation-header-name');
var currentConversation;
// Find the correct conversation window
for(i = 0; i < conversationHeaderNames.length; i++){
    if(conversationHeaderNames[i].innerHTML.trim() == ChannelName){
        currentConversation = conversationHeaderNames[i].parentNode.parentNode;
        break;
    }
}
if(!currentConversation) return; // No conversation with chat bot

а потом мне просто нужно заменить document на currentConversation и все работает.

person Mthenn    schedule 14.07.2016