diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d095a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +config.yml diff --git a/README.md b/README.md index 61bd623..b8e6e0b 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,36 @@ # discord-link-opener Automatically open browser tabs when links matching given constraints are sent in discord channels. +# Disclaimer +Use at own risk! + +Automating normal user accounts (generally called "self-bots") is against the [Discord Guidelines](https://discord.com/guidelines) and may result in an account termination (ban) without prior notice. + # Installation and Usage -1. Download Python 3.6.x or 3.7.x . Before installing, make sure to check “Add Python to PATH”. -2. Once installed, open CMD and type: - pip install discord.py[voice] and - pip install asyncio -3. Download Link Opener: https://github.com/clearyy/discord-link-opener -4. Copy open.py to your desktop. -5. Right click open.py and select “Edit with IDLE”. Once in the code, only do the following two things: - Add the discord channel IDs (separated by commas) that you would like to monitor. - Add your Discord token. (Tutorial on how to find your token: - https://www.youtube.com/watch?v=tI1lzqzLQCs) - Do not edit the keyword and blacklist lines. -6. Save the file. -7. Run open.py and you will be prompted for keywords and blacklisted words. Enter words in lowercase, separated by spaces and press enter when completed. -8. Wait for the bot to automatically open Chrome browser tabs when links matching given constraints are sent in the specified discord channels. -9. Cook. -10. To change keywords at any point, press Ctrl + c to terminate the script. Then simply run the script again and enter new words when prompted. +1. Download Python 3.6.x or 3.7.x or 3.8.x . Before installing, make sure to check “Add Python to PATH”. +2. Once installed, open CMD and type: +``` +pip install discord.py[voice] +pip install asyncio +pip install pyyaml +``` +3. Download Link Opener: https://github.com/Smidelis/discord-link-opener/ +4. Extract the contents of the *.zip file to a local folder of your choice (desktop/documents/...) +5. Copy config_example.yaml and rename it to config.yml. +6. Open the config.yml and replace the placeholders with the values for the token (tutorial on how to find your token: https://www.youtube.com/watch?v=tI1lzqzLQCs), the keywords you're looking for, the blacklisted words and the channels. +7. Three browsers have been implemented: chrome, edgechromium and firefox. Change the user_choice to the value of your preferred browser. +8. Save the file. +9. Open PowerShell/CMD and change directory (cd) to the folder, where you have extracted the *.zip file to. +10. Run open.py. +11. Wait for the bot to automatically open new browser tabs when links matching given constraints are sent in the specified discord channels. +12. Cook. # Requirements -asyncio, discord.py +asyncio, discord.py, pyyaml # Operating Systems This was designed for and only tested on windows. +# Credits +This script is a combination of the versions by clearyy and Vincentt1705 and some own ideas. Thanks for the inspiration! +Config files added by elevul. diff --git a/bell.wav b/bell.wav new file mode 100644 index 0000000..1e0fd88 Binary files /dev/null and b/bell.wav differ diff --git a/config_example.yaml b/config_example.yaml new file mode 100644 index 0000000..b285bea --- /dev/null +++ b/config_example.yaml @@ -0,0 +1,25 @@ +token: discordtoken +filters: + keywords: + - 3090 + - 3080 + - 3070 + - 3060 + blacklist: + #If you don't want any value in the blacklist set it to null, otherwise replace it with the words you want to blacklist + - null +various: + playBellSound: True +channels: + - 123456789123456789 + - 123456789123456789 + - 123456789123456789 +browsers: + chrome: + path: 'C:\Program Files\Google\Chrome\Application\chrome.exe' + edgechromium: + path: 'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe' + firefox: + path: 'C:\Program Files\Mozilla Firefox\firefox.exe' + #replace with the name of any of the browsers in the list above. Default is chrome + user_choice: 'chrome' \ No newline at end of file diff --git a/open.py b/open.py index 3a7afc4..a28ae5d 100644 --- a/open.py +++ b/open.py @@ -1,84 +1,135 @@ +''' +Script to monitor links sent to discord channels and opening them in a new browser tab. +Adapted to monitor links sent by https://partalert.net/join-discord + +by https://github.com/Smidelis +based on https://github.com/clearyy/discord-link-opener and https://github.com/Vincentt1705/partalert-link-opener + +''' + import webbrowser import asyncio -import discord from discord.ext.commands import Bot -from discord.ext import commands import re - -''' -by cleary#6546 // @preorderd -''' +import winsound +from datetime import datetime +import urllib.parse as urlparse +from urllib.parse import parse_qs +import yaml #pylint: disable=anomalous-backslash-in-string -client = Bot('adawd@@#^^') +client = Bot('KarlaKolumna') client.remove_command('help') -#prompt user enter keywords to check for in links -keywords = list(map(str,input("Enter keywords seperated by space: ").split())) +#Pulling configuration from yaml file +with open("config.yml", "r") as ymlfile: + cfg = yaml.load(ymlfile, Loader=yaml.FullLoader) + +#Registering the browsers and preparing the choice +webbrowser.register('chrome', None, webbrowser.BackgroundBrowser(cfg['browsers']['chrome']['path'])) +webbrowser.register('edgechromium', None, webbrowser.BackgroundBrowser(cfg['browsers']['edgechromium']['path'])) +webbrowser.register('firefox', None, webbrowser.BackgroundBrowser(cfg['browsers']['firefox']['path'])) +browserchoice = cfg['browsers']['user_choice'] -#prompt user to enter negative keywords that will prevent a browser window from opening to have no blacklisted words, press enter right away -blacklist = list(map(str,input("Enter blacklisted keywords seperated by space: ").split())) +# Pulling keywords from yml config file +keywords = cfg['filters']['keywords'] -#enter channel id(s) where links would be picked up (monitor channel id) seperated by commas. these should be ints -channels = [] +# Pulling blacklist from yml file and accounting for it being null +black = cfg['filters']['blacklist'] +if black == [None]: + blacklist = '' +else: + blacklist = black +print(blacklist) -#enter token of discord account that has access to watch specified channels -token = '' +# Pulling channels from yml file +channels = cfg['channels'] + +# Pulling token from the yml file +token = cfg['token'] global start_count start_count = 0 -#check for keywords and blacklisted words in message urls and open browser if conditions are met -async def check_urls(urls): +# Decide whether you want to hear a bell sound when a link is opened (True/False) +playBellSound = cfg['various']['playBellSound'] + +# Based on https://github.com/Vincentt1705/partalert-link-opener +# Function to print the current time before the information about the link. +def print_time(*content): + """ + Can be used as a normal print function but includes the current date and time + enclosed in brackets in front of the printed content. + :param content: The content you would normally put in a print() function + """ + now = datetime.now() + date_time = now.strftime("%d/%m/%Y %H:%M:%S") + print(f"[{date_time}] - [INFO] ", *content) + +# Function to build the amazon url, where partalert is redirecting to +# Obsolete, as partalert URL is not containing Amazon information anymore. +def get_amazon_url(url): + """ + This function collects and returns an amazon link + that would be linked through the green button on the webpage. + :param url: An partalert.net link for an amazon product + :return: The extracted amazon link to the product + """ + + # Parse url to obtain query parameters + parsed = urlparse.urlparse(url) + + country = parse_qs(parsed.query)['tld'][0] + prod_id = parse_qs(parsed.query)['asin'][0] + tag = parse_qs(parsed.query)['tag'][0] + smid = parse_qs(parsed.query)['smid'][0] + + # Create full Amazon url + url = f"https://www.amazon{country}/dp/{prod_id}?tag={tag}&linkCode=ogi&th=1&psc=1&smid={smid}" + return url + +# Check for keywords and blacklisted words in message urls and open browser if conditions are met +async def check_urls(urls, channel_name): for url in urls: if any(x in url.lower() for x in keywords) and all(x not in url.lower() for x in blacklist): - #enter path to chrome here, for windows 10, this should work - webbrowser.get("C:/Program Files (x86)/Google/Chrome/Application/chrome.exe %s").open(url) - print(f'Opened {url}') + webbrowser.get(browserchoice).open_new_tab(url) + print_time(f'Link opened from #{channel_name}: {url}') + if playBellSound: + winsound.PlaySound('bell.wav', winsound.SND_FILENAME) + +async def get_last_msg(channelid): + msg = await client.get_channel(channelid).history(limit=1).flatten() + return msg[0] @client.event -async def on_message(message): - global start_count - # temporary bypass to weird d.py cacheing issue - # only print this info on the first time the client launches. this is due to d.py calling on_ready() after the bot regains connection - if start_count == 0: - print('\n{} is ready to cop some restocks.\n'.format(str(client.user))) - if len(keywords) >= 1 and keywords[0] != '': - print('Watching for keywords {}.\n'.format(', '.join(keywords))) - else: - print('No keywords have been provided.\n') - if len(blacklist) > 0: - print('Ignoring keywords {}.\n'.format(', '.join(blacklist))) - else: - print('No keywords currently blacklisted.\n') - start_count += 1 +async def on_ready(): + print_time('{} is ready to watch for links.'.format(str(client.user))) + if len(keywords) >= 1 and keywords[0] != '': + print_time('Watching for keywords {}.'.format(', '.join(keywords))) else: - if message.channel.id in channels: - if message.embeds: - for embed in message.embeds: - toembed = embed.to_dict() - if str(toembed['type']).lower() != 'link': - urls = re.findall("(?:(?:https?|ftp):\/\/|\b(?:[a-z\d]+\.))(?:(?:[^\s()<>]+|\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))?\))+(?:\((?:[^\s()<>]+|(?:\(?:[^\s()<>]+\)))?\)|[^\s`!()\[\]{};:'.,<>?«»“”‘’]))?",toembed['title']) - if urls: - await check_urls(urls) - try: - urls2 = re.findall("(?:(?:https?|ftp):\/\/|\b(?:[a-z\d]+\.))(?:(?:[^\s()<>]+|\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))?\))+(?:\((?:[^\s()<>]+|(?:\(?:[^\s()<>]+\)))?\)|[^\s`!()\[\]{};:'.,<>?«»“”‘’]))?",toembed['description']) - if urls2: - await check_urls(urls2) - except: - pass - try: - for field in toembed['fields']: - urls3 = re.findall("(?:(?:https?|ftp):\/\/|\b(?:[a-z\d]+\.))(?:(?:[^\s()<>]+|\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))?\))+(?:\((?:[^\s()<>]+|(?:\(?:[^\s()<>]+\)))?\)|[^\s`!()\[\]{};:'.,<>?«»“”‘’]))?",str(field)) - if urls3: - await check_urls(urls3) - except: - pass - if message.content != '': - print(message.content) - urls4 = re.findall("(?:(?:https?|ftp):\/\/|\b(?:[a-z\d]+\.))(?:(?:[^\s()<>]+|\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))?\))+(?:\((?:[^\s()<>]+|(?:\(?:[^\s()<>]+\)))?\)|[^\s`!()\[\]{};:'.,<>?«»“”‘’]))?",message.content) - if urls4: - await check_urls(urls4) + print_time('No keywords have been provided.') + if len(blacklist) > 0: + print_time('Ignoring keywords {}.'.format(', '.join(blacklist))) + else: + print_time('No keywords currently blacklisted.') -client.run(token,bot=False) \ No newline at end of file +# Fixed discordpy not able to read embeds anymore. Thanks to dubble#0001 on Discord. +@client.event +async def on_message(message): + if message.channel.id in channels: + await asyncio.sleep(0.3) + try: + last_msg = await get_last_msg(message.channel.id) + fields = last_msg.embeds[0].fields + linkembed = next(x for x in fields if x.name == "Link") + urls = re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', linkembed.value if linkembed else "") + for url in urls: + await check_urls(urls, message.channel.name) + except: + if message.content != '': + urls = re.findall("(?:(?:https?|ftp):\/\/)?[\w/\-?=%.#&+]+\.[\w/\-?=%.#&+]+",message.content) + + if urls: + asyncio.ensure_future(check_urls(urls, message.channel.name)) +client.run(token,bot=False)