File size: 8,820 Bytes
10a95dd
dd2dd36
a36bc66
dd2dd36
00d90ae
dd2dd36
3291ddb
 
ef02423
d7e9769
ef02423
3291ddb
dd2dd36
 
 
3152d9e
10a95dd
3152d9e
dd2dd36
 
 
 
 
 
 
cf8e5a9
 
 
 
 
3291ddb
 
 
 
ef02423
 
 
 
 
10a95dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55464af
3291ddb
c981d80
 
3291ddb
 
 
ef02423
3291ddb
10a95dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ef02423
4c3086f
 
00d90ae
4c3086f
 
10a95dd
00d90ae
 
 
ef02423
00d90ae
4c3086f
 
 
ef02423
 
10a95dd
4c3086f
 
 
10a95dd
905f4ca
4c3086f
 
 
 
10a95dd
4c3086f
ef02423
00d90ae
4c3086f
ef02423
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4c3086f
 
 
 
 
 
 
 
10a95dd
4c3086f
10a95dd
ef02423
d7e9769
905f4ca
ef02423
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cf8e5a9
ef02423
 
 
905f4ca
ef02423
 
cf8e5a9
 
 
03a5cdb
ef02423
 
 
 
03a5cdb
ef02423
 
d7e9769
 
 
ef02423
d7e9769
 
 
905f4ca
 
ef02423
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# This is an quote and post library for a specific thread in the WarOnline forum.

import WarClient
import requests
import re
from bs4 import BeautifulSoup
import urllib.request as urllib
import warnings
#import schedule
import time
#from tqdm import tqdm
warnings.filterwarnings("ignore")

# Define the login URL and the thread URL
login_url = 'https://waronline.org/fora/index.php?login/login'
thread_url = 'https://waronline.org/fora/index.php?threads/warbot-playground.17636/'
post_url = "https://waronline.org/fora/index.php?threads/warbot-playground.17636/add-reply"

# Define the login credentials
username = 'WarBot'
password = 'naP2tion'

# Start a session to persist the login cookie across requests
session = requests.Session()

def fixString(S):
    # Substitute multiple commas with a single one
    S = re.sub(",+", ",", S)
    return S

def compare_pages(url1, url2):
    #Compares 2 pages and returns True if they are the same
    return urllib.urlopen(url1).geturl() == urllib.urlopen(url2).geturl()

def remove_non_english_russian_chars(s):
    # Regular expression to match all characters that are not in English or Russian
    pattern = '[^0-9A-Za-zА-Яа-яЁё(),.!?"\s-]'
    # Replace all matched characters with an empty string
    return re.sub(pattern, '', s)
def login(username=username, password=password, thread_url=thread_url):
    # Log-In to the forum and redirect to thread

    # Retrieve the login page HTML to get the CSRF token
    login_page_response = session.get(login_url)
    soup = BeautifulSoup(login_page_response.text, 'html.parser')
    csrf_token = soup.find('input', {'name': '_xfToken'})['value']

    # Login to the website
    login_data = {
        'login': username,
        'password': password,
        'remember': '1',
        '_xfRedirect': thread_url,
        '_xfToken': csrf_token
    }
    response = session.post(login_url, data=login_data)

    # Check if the login was successful
    if 'Invalid login' in response.text:
        print('Login failed!')
        exit()

def post(message="", thread_url=thread_url, post_url=post_url, quoted_by="",quote_text="",quote_source=""):
    #Post a message to the forum (with or without the quote
    #quote_source is in format 'post-3920992'
    quote_source = quote_source.split('-')[-1] # Take the numbers only

    if quoted_by:
        message = f'[QUOTE="{quoted_by}, post: {quote_source}"]{quote_text}[/QUOTE]{message}'
        #message = f'[QUOTE="{quoted_by}, data-source=post: {quote_source}"]{quote_text}[/QUOTE]{message}'
        # optionally add @{quoted_by} to indent the quoter

    # Retrieve the thread page HTML
    response = session.get(thread_url)

    # Parse the HTML with BeautifulSoup
    soup = BeautifulSoup(response.text, 'html.parser')

    # Extract the _xfToken value from the hidden form field
    xf_token = soup.find('input', {'name': '_xfToken'}).get('value')

    # Construct the message data for the POST request
    message_data = {
        '_xfToken': xf_token,
        'message': message,
        'attachment_hash': '',
        'last_date': '',
        '_xfRequestUri': post_url,
        '_xfWithData': '1',
        '_xfResponseType': 'json'
    }

    response = session.post(post_url, data=message_data)

    # Check if the post was successful
    if not response.ok:
        print('Post failed!')
        exit()

    print('Post submitted successfully.')

def getMessages(thread_url=thread_url, quotedUser="", startingPage=1):
    # Returns all the quotes for #username in the specific multi-page thread url
    allquotes =[]

    page = startingPage  # Counter
    lastPage = False

    # Initial values for messangerName and the message ID
    messengerName = ""
    messageID = ""
    quotedID = ""

    # Patterns to search in the last quote.
    namePattern = re.compile('data-lb-caption-desc="(.*?) ·')
    messageIDPattern = re.compile('data-lb-id="(.*?)"')
    quotedIDPattern = re.compile('data-source="(.*?)"')
    quotedNamePattern = re.compile('data-quote="(.*?)"')

    while not lastPage:
        response = requests.get(thread_url + 'page-' + str(page))
        if response.status_code == 200:

            # Core of the function
            html_content = response.content

            # Parse the HTML content using BeautifulSoup
            soup = BeautifulSoup(html_content, 'html.parser')

            # Find all the message in the thread page
            messageData = soup.find_all('div', {'class': 'message-userContent lbContainer js-lbContainer'})

            for data in messageData:
                try:
                    # Get the messager username
                    matchName = namePattern.search(str(data))
                    if matchName:
                        messengerName = matchName.group(1)

                    # Get the quoted ID
                    matchID = quotedIDPattern.search(str(data))
                    if matchID:
                        quotedID = matchID.group(1)

                    # Get the message ID
                    matchID = messageIDPattern.search(str(data))
                    if matchID:
                        messageID = matchID.group(1)

                    matchQuotedName = quotedNamePattern.search(str(data))
                    if matchQuotedName:
                        quotedName = matchQuotedName.group(1)
                    if quotedUser and (quotedUser != quotedName):
                        continue

                    # Make sure that the messages have a quote inside
                    blockquote = data.find('blockquote')
                    if blockquote:
                        # Extract the text
                        text = data.find('div', {'class': 'bbWrapper'})
                        for bq in text.find_all('blockquote'):
                            bq.extract()
                        reply = text.get_text().replace('\n', ' ').strip()

                        allquotes.append({'reply': reply, 'messengerName': messengerName, 'messageID': messageID, 'quotedID': quotedID})

                except:
                    continue # There was no text in quote, move next

            #check if that is not a last page
            if not compare_pages(thread_url + 'page-' + str(page), thread_url + 'page-' + str(page + 1)):
                page += 1
            else:
                lastPage = True
        else:
            lastPage = True

    return allquotes

# Core Engine of the Client
def WarOnlineBot():

    login(username=username, password=password, thread_url=thread_url)
    #print("logged in")

    # All messages (with quotes) by ALL users:
    allMessages = getMessages(thread_url=thread_url, quotedUser='', startingPage=1)

    # IDs of the quoted messages, replied by the bot:
    messages_by_bot_IDs = []

    for msg in allMessages:
        # Set a list of replied messages IDs
        if msg['messengerName'] == username: #message posted by the WarBot
            messages_by_bot_IDs.append(msg['quotedID'].split(': ')[-1])
    # remove empty and repeated elements
    messages_by_bot_IDs = list(set([elem for elem in messages_by_bot_IDs if elem]))

    # All messages (with quotes) sent _FOR_ the Bot:
    messagesForBot = getMessages(thread_url=thread_url, quotedUser=username, startingPage=1)

    # IDs of the messages, quoting the bot:
    messages_for_bot_IDs = []

    for msg in messagesForBot:
        # Set a list of posted message IDs
        messages_for_bot_IDs.append(msg['messageID'].split('-')[-1])
    # remove empty elements
    messages_for_bot_IDs = [elem for elem in messages_for_bot_IDs if elem]

    # Filter to leave just the unanswered messages IDs:
    messages_for_bot_IDs = [ID for ID in messages_for_bot_IDs if ID not in messages_by_bot_IDs]

    # Reply the unanswered messages:
    for msg in messagesForBot:
        if msg['messageID'].split('-')[-1] in messages_for_bot_IDs:

            originalQuote = msg['reply']
            quote = remove_non_english_russian_chars(msg['reply'])
            message = ""

            while not message:
                message = WarClient.getReply(message=quote)

            # Post-processing fixes:
            message = fixString(message)

            print('Quote: ', originalQuote)
            print('Reply: ', message)

            login(username=username, password=password, thread_url=thread_url)
            time.sleep(1)
            post(message=message, thread_url=thread_url, post_url=post_url, quoted_by=msg['messengerName'], quote_text=originalQuote, quote_source=msg['messageID'])

            time.sleep(10)  # Standby time for server load release


if __name__ == '__main__':
    timeout = 5 # min

    # Start the scheduler
    while True:
        WarOnlineBot()

        timer = range(60 * timeout)
        for t in timer:
            time.sleep(1)