Init
This commit is contained in:
commit
8a43fd1050
|
@ -0,0 +1,3 @@
|
|||
# Fediverse Bots
|
||||
|
||||
I used to be on [Fediverse](https://fediverse.party/en/fediverse/) a lot, mainly [Pleroma](https://pleroma.social/). During that time I created a bunch of dumb bots for fun and basic Python/shell script practice. Install accordingly to their own READMEs, if there is none it means you should just create a `token.dat` with it and provide there bot's account token, that's it.
|
|
@ -0,0 +1,3 @@
|
|||
token.dat
|
||||
venv
|
||||
*.log
|
|
@ -0,0 +1,20 @@
|
|||
# maid-bot
|
||||
|
||||
Another bot for posting arts to your fediverse timeline.
|
||||
|
||||
### Initial setup
|
||||
|
||||
* Create sources.dat file and fill them with URLs where
|
||||
```
|
||||
source_url_to_wget hyperlink_url_to_put_in_post_description
|
||||
source_url_to_wget hyperlink_url_to_put_in_post_description
|
||||
source_url_to_wget hyperlink_url_to_put_in_post_description
|
||||
source_url_to_wget hyperlink_url_to_put_in_post_description
|
||||
|
||||
. . . . . . . . . . etc
|
||||
```
|
||||
* Fill token.dat with bot's auth token.
|
||||
* Edit post-local.sh and write custom text. in "status" field of POST json.
|
||||
* Now put it to crontab!
|
||||
|
||||
The bot will take random pair of URLs from the file, download the image itself by the first url and post it to fedi, attaching the second url as description.
|
|
@ -0,0 +1,49 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [ -z $(which jq) ]
|
||||
then
|
||||
echo "Missing jq package, please install"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
token_dat="./token.dat"
|
||||
|
||||
if [ ! -f $token_dat ]
|
||||
then
|
||||
echo "Missing ./token.dat"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sources_dat="./sources.dat"
|
||||
|
||||
if [ ! -f $sources_dat ]
|
||||
then
|
||||
echo "Missing ./sources.dat"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
api_base_url="https://your.site/"
|
||||
access_token="$(cat ${token_dat})"
|
||||
|
||||
pair_to_post=($(cat ${sources_dat} | shuf -n 1))
|
||||
source_url=${pair_to_post[0]}
|
||||
hyperlink_url=${pair_to_post[1]}
|
||||
|
||||
mkdir source
|
||||
cd source
|
||||
wget "${source_url}" 2> /dev/null || (echo "Error with ${source_url}" && exit 1)
|
||||
|
||||
media_json=$(curl -X POST "${api_base_url}/api/v1/media" \
|
||||
-H "Authorization: Bearer ${access_token}" \
|
||||
-F "file=@`ls *`")
|
||||
|
||||
media_id=$(jq -r ".id" <<< ${media_json})
|
||||
|
||||
echo $media_json
|
||||
cd ..
|
||||
rm -rf source/
|
||||
|
||||
curl -X POST -d '{"status":" :azrn_shiratsuyu_maid: '${hyperlink_url}'", "visibility":"'unlisted'", "media_ids":'[\"${media_id}\"]'}' \
|
||||
-H "Authorization: Bearer ${access_token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${api_base_url}/api/v1/statuses"
|
|
@ -0,0 +1 @@
|
|||
token.dat
|
|
@ -0,0 +1,53 @@
|
|||
#!/home/naiji/mastodon/maritalk-bot/venv/bin/python
|
||||
import sys
|
||||
import numpy as np
|
||||
|
||||
from mastodon import Mastodon
|
||||
|
||||
# --------------------------------------------------
|
||||
|
||||
def main():
|
||||
|
||||
mastodon = Mastodon(
|
||||
access_token = 'token.dat',
|
||||
api_base_url = 'https://your.site/'
|
||||
)
|
||||
|
||||
text = open('source.dat', encoding='utf8').read()
|
||||
|
||||
# ORIGINAL IMPLEMENTATION:
|
||||
# https://gist.github.com/bpshaver/840d53222b72d2612ddf6702ef020274#file-markov_text_sim-py
|
||||
|
||||
source = text.split()
|
||||
|
||||
def make_pairs(source):
|
||||
for i in range(len(source)-1):
|
||||
yield (source[i], source[i+1])
|
||||
|
||||
pairs = make_pairs(source)
|
||||
|
||||
word_dict = {}
|
||||
|
||||
for left_w, right_w in pairs:
|
||||
if left_w in word_dict.keys():
|
||||
word_dict[left_w].append(right_w)
|
||||
else:
|
||||
word_dict[left_w] = [right_w]
|
||||
|
||||
first_word = np.random.choice(source)
|
||||
while first_word.islower():
|
||||
first_word = np.random.choice(source)
|
||||
|
||||
chain = [first_word]
|
||||
|
||||
ch = ''
|
||||
|
||||
while not ch.endswith('.'):
|
||||
ch = np.random.choice(word_dict[chain[-1]])
|
||||
chain.append(ch)
|
||||
|
||||
toot = ' '.join(chain)
|
||||
mastodon.status_post(toot, media_ids=None, visibility='unlisted')
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
|
@ -0,0 +1,38 @@
|
|||
acme==1.1.0
|
||||
certbot==0.40.0
|
||||
certbot-nginx==0.40.0
|
||||
certifi==2019.11.28
|
||||
chardet==3.0.4
|
||||
ConfigArgParse==0.13.0
|
||||
configobj==5.0.6
|
||||
cryptography==2.8
|
||||
dbus-python==1.2.16
|
||||
distro==1.4.0
|
||||
distro-info===0.23ubuntu1
|
||||
future==0.18.2
|
||||
idna==2.8
|
||||
josepy==1.2.0
|
||||
mock==3.0.5
|
||||
netifaces==0.10.4
|
||||
parsedatetime==2.4
|
||||
pbr==5.4.5
|
||||
PyGObject==3.36.0
|
||||
pymacaroons==0.13.0
|
||||
PyNaCl==1.3.0
|
||||
pyOpenSSL==19.0.0
|
||||
pyparsing==2.4.6
|
||||
pyRFC3339==1.1
|
||||
python-apt==2.0.0+ubuntu0.20.4.1
|
||||
python-debian===0.1.36ubuntu1
|
||||
pytz==2019.3
|
||||
PyYAML==5.3.1
|
||||
requests==2.22.0
|
||||
requests-toolbelt==0.8.0
|
||||
six==1.14.0
|
||||
ubuntu-advantage-tools==20.3
|
||||
ufw==0.36
|
||||
urllib3==1.25.8
|
||||
zope.component==4.3.0
|
||||
zope.event==4.4
|
||||
zope.hookable==5.0.0
|
||||
zope.interface==4.7.1
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
source venv/bin/activate
|
||||
python3 post.py
|
||||
deactivate
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,16 @@
|
|||
# morrowsay-bot
|
||||
|
||||
A dumb bot to post random generic quotes to your fediverse timeline!
|
||||
|
||||
### How to run ###
|
||||
* For posting you can use already pre-saved quotes from the repository. If you want "your own", you can...
|
||||
* ...download quotes:
|
||||
```bash
|
||||
python3 loadquotes.py
|
||||
```
|
||||
* To make a single post with a random quote from the gotten file, run `post.py`
|
||||
* Don't forget to setup your bot account, get access tokens and establish the environment around it. I am not providing any instructions of how to do it, since all the steps are different and depend on what, where and how you want to run the bot.
|
||||
|
||||
* That's all!
|
||||
|
||||
![alt text](https://i.imgur.com/3ao6VLt.png)
|
|
@ -0,0 +1,30 @@
|
|||
import sys
|
||||
import os.path as op
|
||||
from urllib.parse import urlparse
|
||||
from pprint import pprint
|
||||
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
# --------------------------------------------------
|
||||
|
||||
URL = "https://elderscrolls.fandom.com/wiki/Generic_Dialogue_(Morrowind)"
|
||||
|
||||
def main():
|
||||
|
||||
|
||||
print('REQUEST ' + URL)
|
||||
resp = requests.get(URL)
|
||||
soup = BeautifulSoup(resp.text, 'lxml')
|
||||
|
||||
print('DOWNLOADING')
|
||||
res = [icont.string for icont in soup('i') if icont.string is not None]
|
||||
|
||||
with open('quotes.dat', 'w', encoding='utf-8') as file:
|
||||
for quote in res:
|
||||
print(quote, file=file)
|
||||
|
||||
print('YAY SUCCESS!\n\n! ! ! Now don\'t forget to run replacevars.py ! ! !')
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
|
@ -0,0 +1,29 @@
|
|||
import sys
|
||||
import random
|
||||
import datetime
|
||||
import os.path as op
|
||||
from pprint import pprint
|
||||
|
||||
import requests
|
||||
from mastodon import Mastodon
|
||||
|
||||
# --------------------------------------------------
|
||||
|
||||
def main():
|
||||
|
||||
mastodon = Mastodon(
|
||||
access_token = 'token.dat',
|
||||
api_base_url = 'https://your.site/'
|
||||
)
|
||||
|
||||
with open('quotes.dat', 'r', encoding='utf-8') as file:
|
||||
data = file.readlines()
|
||||
|
||||
quote = data[random.randint(0, len(data))]
|
||||
toot = quote
|
||||
|
||||
mastodon.status_post(toot, media_ids=None, visibility='unlisted')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,64 @@
|
|||
import sys
|
||||
import os.path as op
|
||||
|
||||
# --------------------------------------------------
|
||||
|
||||
VARIABLES = {
|
||||
|
||||
'[PC Guild Rank]\nLike in \"[PC Guild Rank], what can be said. We are the few, the proud, the ... under-paid! HarHarHar!\"':
|
||||
'[PC Guild Rank]',
|
||||
|
||||
'[Speaker\'s Name]\nLike in \"But perhaps [Speaker\'s Name] should not speak about this in public. And who would listen, anyway?\"':
|
||||
'[Speaker\'s Name]',
|
||||
|
||||
'[PC Name]\nLike in \"[PC Name]. Once before, Lord Nerevar thought Dagoth Ur and all his kin were dead.\"':
|
||||
'[PC Name]',
|
||||
|
||||
'[PC Race]\nLike in \"I don\'t like you, [PC Race]. You better stay out of this.\"':
|
||||
'[PC Race]',
|
||||
|
||||
'[PC Rank]\nLike in \"What do you want, [PC Rank]?\"':
|
||||
'[PC Rank]',
|
||||
|
||||
'[Next PC Rank]\nLike in "You are now [PC Name] the [Next PC Rank] in the Fighters Guild.\"':
|
||||
'[Next PC Rank]',
|
||||
|
||||
'[Faction]\nLike in \"The [Faction] can forgive your actions this one time only, [PC Rank] [PC Name].\"':
|
||||
'[Faction]',
|
||||
|
||||
'[Rank]\nLike in \"I\'ve risen to [Rank] rank in this outfit by being smart and careful.\"':
|
||||
'[Rank]',
|
||||
|
||||
'[Name]\nLike in \"Hello, [PC Name]. I\'m [Name], and I\'m here to clean out this den of Daedra worshippers.\"':
|
||||
'[Name]'
|
||||
}
|
||||
|
||||
# Replaces [macros] with strings you want
|
||||
|
||||
def main():
|
||||
|
||||
with open('quotes.dat', 'r', encoding='utf-8') as file:
|
||||
quotes = file.readlines()
|
||||
|
||||
replacer = ''
|
||||
|
||||
if (input('Do you want to remove broken strings? y/n ') == 'y'):
|
||||
quotes.remove('The Elder Scrolls III: Morrowind\n')
|
||||
for quote in quotes:
|
||||
if (len(quote) < 5 or not quote.strip().endswith('\"') or not quote.strip().startswith('\"')):
|
||||
quotes.remove(quote)
|
||||
|
||||
for to_print, to_replace in VARIABLES.items():
|
||||
while not replacer.strip():
|
||||
replacer = input('\n' + to_print + '\n Input what do you want to replace ' + to_replace + ' with:')
|
||||
for i, quote in enumerate(quotes):
|
||||
quotes[i] = quote.replace(to_replace, replacer)
|
||||
replacer = ''
|
||||
|
||||
|
||||
with open('quotes.dat', 'w', encoding='utf-8') as file:
|
||||
for quote in quotes:
|
||||
print(quote, file=file, end='')
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
|
@ -0,0 +1,19 @@
|
|||
requests==2.22.0
|
||||
requests-oauthlib==1.2.0
|
||||
beautifulsoup4==4.8.0
|
||||
certifi==2019.6.16
|
||||
chardet==3.0.4
|
||||
decorator==4.4.0
|
||||
idna==2.8
|
||||
lxml==4.3.4
|
||||
Mastodon.py==1.4.6
|
||||
oauthlib==3.0.2
|
||||
PySocks==1.7.0
|
||||
python-dateutil==2.8.0
|
||||
python-docx==0.8.10
|
||||
python-magic==0.4.15
|
||||
pytz==2019.2
|
||||
six==1.12.0
|
||||
soupsieve==1.9.2
|
||||
tweepy==3.8.0
|
||||
urllib3==1.25.3
|
|
@ -0,0 +1,21 @@
|
|||
# music-bot
|
||||
|
||||
Another useless bot for posting garbage to your timeline.
|
||||
|
||||
### Initial setup
|
||||
|
||||
* Have installed
|
||||
* curl
|
||||
* jq
|
||||
* exiftool
|
||||
* Create ./music/ folder
|
||||
* In ./music/ folder create separate folders for each release (albums/singles/etc.)
|
||||
* In each ./music/*/
|
||||
* put music files
|
||||
* put a corresponding cover image named 'cover.jpg' to attach together with a music file
|
||||
* put a simple file named 'link' and copypaste there a url to corresponding information about the release
|
||||
* Edit post.sh
|
||||
* change instance url from your.site to whatever you have
|
||||
* optionally edit status message in the last POST curl
|
||||
* Be careful, because by default it is assumed all music has .opus extension. If it is not your case please handle the situation however you need.
|
||||
* Now put it to crontab!
|
|
@ -0,0 +1,69 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [ -z $(which jq) ]
|
||||
then
|
||||
echo "Missing jq package, please install"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
token_dat="./token.dat"
|
||||
|
||||
if [ ! -f $token_dat ]
|
||||
then
|
||||
echo "Missing ./token.dat"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sources_dat="./music"
|
||||
|
||||
if [ ! -d $sources_dat ]
|
||||
then
|
||||
echo "Missing ./music/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ 0 -eq $(ls ./music | wc -l) ]
|
||||
then
|
||||
mv posted_already/* music/
|
||||
fi
|
||||
|
||||
api_base_url="https://your.site/"
|
||||
access_token="$(cat ${token_dat})"
|
||||
|
||||
folder_name=$(ls music/ | shuf -n 1)
|
||||
track_name=$(ls music/"${folder_name}" | grep opus | shuf -n 1)
|
||||
|
||||
echo "From: $folder_name"
|
||||
echo "Pick: $track_name"
|
||||
echo " "
|
||||
|
||||
cp -f music/"$folder_name"/"$track_name" temp.opus
|
||||
cp -f music/"$folder_name"/cover.jpg ./cover.jpg
|
||||
|
||||
link=$(cat music/"$folder_name"/link)
|
||||
full_title=$(exiftool -s -s -s -Title temp.opus)
|
||||
full_artist=$(exiftool -s -s -s -Artist temp.opus)
|
||||
|
||||
media_cover_json=$(curl -X POST "${api_base_url}/api/v1/media" \
|
||||
-H "Authorization: Bearer ${access_token}" \
|
||||
-F "file=@`ls cover.*`")
|
||||
|
||||
media_music_json=$(curl -X POST "${api_base_url}/api/v1/media" \
|
||||
-H "Authorization: Bearer ${access_token}" \
|
||||
-F "file=@`ls temp.opus`")
|
||||
|
||||
media_cover_id=$(jq -r ".id" <<< ${media_cover_json})
|
||||
media_music_id=$(jq -r ".id" <<< ${media_music_json})
|
||||
|
||||
echo $media_json
|
||||
|
||||
curl -X POST -d '{"status":"'"${full_title}"' by _ IT IS A TEST POST _ '"${full_artist}"' :mikulove: '"${link}"'", "visibility":"'unlisted'", "media_ids":'[\"${media_cover_id}\",\"${media_music_id}\"]'}' \
|
||||
-H "Authorization: Bearer ${access_token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${api_base_url}/api/v1/statuses"
|
||||
|
||||
rm -f temp.opus
|
||||
rm -f cover.*
|
||||
|
||||
mkdir -p posted_already/
|
||||
mv music/"$folder_name" posted_already/
|
|
@ -0,0 +1,6 @@
|
|||
/token.dat
|
||||
/venv
|
||||
/urls
|
||||
/sources
|
||||
/arts
|
||||
*.log
|
|
@ -0,0 +1,11 @@
|
|||
# udonge-bot
|
||||
|
||||
Another useless bot for posting arts to your fediverse timeline.
|
||||
|
||||
### Initial setup
|
||||
|
||||
* Install [jq](https://stedolan.github.io/jq/) package for curl json parsing.
|
||||
* Create sfw/ and nsfw/ folders and fill them with arts.
|
||||
* Fill token.dat with bot's auth token.
|
||||
* Optionally modify however you need!
|
||||
* Now put it to crontab!
|
|
@ -0,0 +1,37 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [ -z $(which jq) ]
|
||||
then
|
||||
echo "Missing jq package, please install"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
token_dat="./token.dat"
|
||||
|
||||
if [ ! -f $token_dat ]
|
||||
then
|
||||
echo "Missing ./token.dat"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
api_base_url="https://your.site/"
|
||||
access_token="$(cat ${token_dat})"
|
||||
|
||||
sensitivity="$(ls | grep sfw | shuf -n 1)"
|
||||
source_url="${sensitivity}/$(ls ${sensitivity} | shuf -n 1)"
|
||||
is_sensitive=true
|
||||
if [ "${sensitivity}" == "sfw" ]
|
||||
then
|
||||
is_sensitive=false
|
||||
fi
|
||||
|
||||
media_json=$(curl -X POST "${api_base_url}/api/v1/media" \
|
||||
-H "Authorization: Bearer ${access_token}" \
|
||||
-F "file=@${source_url}")
|
||||
|
||||
media_id=$(jq -r ".id" <<< ${media_json})
|
||||
|
||||
curl -X POST -d '{"status":" My test status..", "sensitive":'${is_sensitive}', "visibility":"'unlisted'", "media_ids":'[\"${media_id}\"]'}' \
|
||||
-H "Authorization: Bearer ${access_token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${api_base_url}/api/v1/statuses"
|
|
@ -0,0 +1 @@
|
|||
token.dat
|
|
@ -0,0 +1,98 @@
|
|||
#!/home/naiji/mastodon/vndb-bot/venv/bin/python
|
||||
|
||||
import re
|
||||
import sys
|
||||
import random
|
||||
import requests
|
||||
import vndb as v # author HarHar (https://github.com/HarHar)
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from mastodon import Mastodon
|
||||
|
||||
URL_HEAD = 'https://vndb.org/v/rand'
|
||||
FORBIDDEN_TAGS = [2023, 156, 162, 897, 391, 98, 2047, 1341, 83]
|
||||
|
||||
def main():
|
||||
#Logging into VNDB
|
||||
vndb = v.VNDB('VNDBbot', '0.1', 'LOGIN', 'PASSWORD')
|
||||
id = -1
|
||||
safe = True
|
||||
|
||||
while True: # Searching for a good vn
|
||||
|
||||
# Taking a random visual novel
|
||||
resp = requests.get(URL_HEAD)
|
||||
soup = BeautifulSoup(resp.text, 'lxml')
|
||||
# Extracting its ID
|
||||
id = int(soup.find('base')['href'].split('v')[2])
|
||||
|
||||
# getting tags of a VN by given random ID
|
||||
vndb_result = vndb.get('vn', 'tags', '(id=' + str(id) + ')', '') # getting all the VNs on VNDB
|
||||
vn_tags = vndb_result['items'][0]['tags']
|
||||
|
||||
good_vn = True #supposing
|
||||
for tag in vn_tags:
|
||||
for forbidden_tag in FORBIDDEN_TAGS:
|
||||
if int(tag[0]) == forbidden_tag:
|
||||
good_vn = False # it contains a bad tag
|
||||
|
||||
if not good_vn:
|
||||
continue
|
||||
|
||||
# getting stats of the VN
|
||||
vndb_result = vndb.get('vn', 'stats', '(id=' + str(id) + ')', '') # getting all the VNs on VNDB
|
||||
vn_stats = vndb_result['items'][0]
|
||||
|
||||
popularity = vn_stats['popularity'] if vn_stats['popularity'] else -1
|
||||
rating = vn_stats['rating'] if vn_stats['rating'] else -1
|
||||
votecount = vn_stats['votecount'] if vn_stats['votecount'] else -1
|
||||
if votecount < 10 or rating < 5 or popularity < 0.8:
|
||||
continue
|
||||
|
||||
# getting details of the VN
|
||||
vndb_result = vndb.get('vn', 'details', '(id=' + str(id) + ')', '') # getting all the VNs on VNDB
|
||||
vn_details = vndb_result['items'][0]
|
||||
|
||||
# even slightly suggestive or slightly violent go to Sensitive, so we skip it
|
||||
if (vn_details['image_flagging']['sexual_avg'] > 1) or (vn_details['image_flagging']['violence_avg'] > 1):
|
||||
safe = False
|
||||
|
||||
# getting basic information of the VN
|
||||
vndb_result = vndb.get('vn', 'basic', '(id=' + str(id) + ')', '')
|
||||
vn_basic = vndb_result['items'][0]
|
||||
|
||||
title = vn_basic['title'] if vn_basic['title'] else ''
|
||||
description = vn_details['description'] if vn_details['description'] else ''
|
||||
released = vn_basic['released'] if vn_basic['released'] else 'unknown'
|
||||
link = 'https://vndb.org/v' + str(id)
|
||||
languages = ''
|
||||
for language in vn_basic['languages']:
|
||||
languages += language + ' '
|
||||
|
||||
# logging in and posting
|
||||
mastodon = Mastodon(
|
||||
access_token = 'token.dat',
|
||||
api_base_url = 'https://your.site/',
|
||||
feature_set = 'pleroma'
|
||||
)
|
||||
|
||||
text = title + '\n- - - - - - - -\n\n' + description + '\n\nReleased: ' + released + '\nPopularity: ' + (str(popularity) if popularity > -1 else 'unknown') + '\nRating:' + str(rating) + '\nLanguages: ' + languages + '\n\n' + link
|
||||
|
||||
# getting screenshots of the VN
|
||||
vndb_result = vndb.get('vn', 'screens', '(id=' + str(id) + ')', '')
|
||||
vn_screens = vndb_result['items'][0]['screens']
|
||||
screens = [ ]
|
||||
counter = 0
|
||||
screens.append(mastodon.media_post(requests.get(vn_details['image']).content, 'image/jpeg'))
|
||||
for screen in vn_screens:
|
||||
if screen['flagging']['sexual_avg'] == 0 and screen['flagging']['violence_avg'] == 0:
|
||||
screens.append(mastodon.media_post(requests.get(screen['image']).content, 'image/jpeg'))
|
||||
counter += 1
|
||||
if counter == 3:
|
||||
break
|
||||
|
||||
mastodon.status_post(text, media_ids=screens, visibility='unlisted', sensitive=not safe, content_type='text/bbcode')
|
||||
break
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
|
@ -0,0 +1,118 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
@author: HarHar (https://github.com/HarHar)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import socket
|
||||
import json
|
||||
import time
|
||||
|
||||
class vndbException(Exception):
|
||||
pass
|
||||
|
||||
class VNDB(object):
|
||||
""" Python interface for vndb's api (vndb.org), featuring cache """
|
||||
protocol = 1
|
||||
def __init__(self, clientname, clientver, username=None, password=None, debug=False):
|
||||
self.sock = socket.socket()
|
||||
|
||||
if debug: print('Connecting to api.vndb.org')
|
||||
self.sock.connect(('api.vndb.org', 19534))
|
||||
if debug: print('Connected')
|
||||
|
||||
if debug: print('Authenticating')
|
||||
if (username == None) or (password == None):
|
||||
self.sendCommand('login', {'protocol': self.protocol, 'client': clientname,
|
||||
'clientver': float(clientver)})
|
||||
else:
|
||||
self.sendCommand('login', {'protocol': self.protocol, 'client': clientname,
|
||||
'clientver': float(clientver), 'username': username, 'password': password})
|
||||
res = self.getRawResponse()
|
||||
if res.find('error ') == 0:
|
||||
raise vndbException(json.loads(' '.join(res.split(' ')[1:]))['msg'])
|
||||
if debug: print('Authenticated')
|
||||
|
||||
self.cache = {'get': []}
|
||||
self.cachetime = 720 #cache stuff for 12 minutes
|
||||
def close(self):
|
||||
self.sock.close()
|
||||
def get(self, type, flags, filters, options):
|
||||
""" Gets a VN/producer
|
||||
|
||||
Example:
|
||||
>>> results = vndb.get('vn', 'basic', '(title="Clannad")', '')
|
||||
>>> results['items'][0]['image']
|
||||
u'http://s.vndb.org/cv/99/4599.jpg'
|
||||
"""
|
||||
args = '{0} {1} {2} {3}'.format(type, flags, filters, options)
|
||||
for item in self.cache['get']:
|
||||
if (item['query'] == args) and (time.time() < (item['time'] + self.cachetime)):
|
||||
return item['results']
|
||||
|
||||
self.sendCommand('get', args)
|
||||
res = self.getResponse()[1]
|
||||
self.cache['get'].append({'time': time.time(), 'query': args, 'results': res})
|
||||
return res
|
||||
|
||||
def sendCommand(self, command, args=None):
|
||||
""" Sends a command
|
||||
|
||||
Example
|
||||
>>> self.sendCommand('test', {'this is an': 'argument'})
|
||||
"""
|
||||
whole = ''
|
||||
whole += command.lower()
|
||||
if isinstance(args, str):
|
||||
whole += ' ' + args
|
||||
elif isinstance(args, dict):
|
||||
whole += ' ' + json.dumps(args)
|
||||
|
||||
output = '{0}\x04'.format(whole)
|
||||
self.sock.send(output.encode('utf-8'))
|
||||
|
||||
def getResponse(self):
|
||||
""" Returns a tuple of the response to a command that was previously sent
|
||||
|
||||
Example
|
||||
>>> self.sendCommand('test')
|
||||
>>> self.getResponse()
|
||||
('ok', {'test': 0})
|
||||
"""
|
||||
res = self.getRawResponse()
|
||||
cmdname = res.split(' ')[0]
|
||||
if len(res.split(' ')) > 1:
|
||||
args = json.loads(' '.join(res.split(' ')[1:]))
|
||||
|
||||
if cmdname == 'error':
|
||||
if args['id'] == 'throttled':
|
||||
raise vndbException('Throttled, limit of 100 commands per 10 minutes')
|
||||
else:
|
||||
raise vndbException(args['msg'])
|
||||
return (cmdname, args)
|
||||
def getRawResponse(self):
|
||||
""" Returns a raw response to a command that was previously sent
|
||||
|
||||
Example:
|
||||
>>> self.sendCommand('test')
|
||||
>>> self.getRawResponse()
|
||||
'ok {"test": 0}'
|
||||
"""
|
||||
finished = False
|
||||
whole = ''
|
||||
while not finished:
|
||||
whole += self.sock.recv(4096).decode('utf-8')
|
||||
if '\x04' in whole: finished = True
|
||||
return whole.replace('\x04', '').strip()
|
|
@ -0,0 +1,2 @@
|
|||
token.dat
|
||||
venv
|
|
@ -0,0 +1 @@
|
|||
392
|
|
@ -0,0 +1,281 @@
|
|||
#!/home/naiji/mastodon/vocaloiddb-bot/venv/bin/python
|
||||
|
||||
import re
|
||||
import sys
|
||||
import random
|
||||
import requests
|
||||
|
||||
import os.path as op
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from mastodon import Mastodon
|
||||
|
||||
MIKUDB_HEAD = 'http://mikudb.moe/page/'
|
||||
MIKUDB_TAIL = '/?s'
|
||||
|
||||
VOCADB_HEAD = 'https://vocadb.net/'
|
||||
|
||||
def findRandomAlbumUrl(last_page_id) -> str:
|
||||
alarm_counter = 0
|
||||
while True and alarm_counter < 5:
|
||||
selection_page_id = random.randint(0, int(last_page_id))
|
||||
resp = requests.get(MIKUDB_HEAD + str(selection_page_id) + MIKUDB_TAIL)
|
||||
soup = BeautifulSoup(resp.text, 'lxml')
|
||||
found_album = True
|
||||
album_entries = soup.findAll('div', {'class': 'searchres album-box grid_19'})
|
||||
if len(album_entries) != 0:
|
||||
found_album = True
|
||||
album_entry = random.choice(album_entries)
|
||||
return str(album_entry.findAll('a', href=True)[0]["href"])
|
||||
else:
|
||||
alarm_counter += 1
|
||||
|
||||
return ""
|
||||
|
||||
def findAlbumImageUrl(soup) -> str:
|
||||
image_soup = soup.findAll('a', {'rel': 'lightbox'})
|
||||
if len(image_soup) == 0:
|
||||
return ""
|
||||
else:
|
||||
return str(image_soup[0]["href"])
|
||||
|
||||
def findAlbumTitle(soup) -> str:
|
||||
title_soup = soup.findAll('h1', {'class': 'album-title'}, text=True)
|
||||
if len(title_soup) == 0:
|
||||
return "UNKOWN TITLE!! somewhat the parser failed... idk, please ping @NaiJi on this post"
|
||||
else:
|
||||
return str(title_soup[0].get_text())
|
||||
|
||||
def main():
|
||||
|
||||
with open('last_page.dat', 'r', encoding='utf-8') as file:
|
||||
last_page_id = file.readlines()[0]
|
||||
|
||||
album_url = findRandomAlbumUrl(last_page_id)
|
||||
print(album_url)
|
||||
if album_url == "":
|
||||
return
|
||||
|
||||
# PARSING ACTUAL ALBUM PAGE
|
||||
|
||||
resp = requests.get(album_url)
|
||||
soup = BeautifulSoup(resp.text, 'lxml')
|
||||
|
||||
image_url = findAlbumImageUrl(soup)
|
||||
album_title = findAlbumTitle(soup)
|
||||
|
||||
# PARSING ALBUM INFO BOX
|
||||
|
||||
info_raw = str(soup.find('div', {'class': 'album-box album-infopost panel panel-default'}))
|
||||
info_splits = info_raw.split('\n')
|
||||
|
||||
if len(info_splits) != 1:
|
||||
|
||||
span_token = '</span>'
|
||||
li_token = '</li>'
|
||||
tag_token = 'rel="tag">'
|
||||
a_token = '</a>'
|
||||
href_token = '<a href="'
|
||||
href_end_token = '">'
|
||||
|
||||
# # # ALTERNATIVE NAME
|
||||
|
||||
alternative_name = ''
|
||||
for split in info_splits:
|
||||
if ' names:' in split:
|
||||
begin = split.find(span_token, 0) + len(span_token)
|
||||
end = split.find(li_token, 0)
|
||||
alternative_name = split[begin : end]
|
||||
break
|
||||
|
||||
# # # TYPE
|
||||
|
||||
type_names = []
|
||||
for split in info_splits:
|
||||
if 'Type:' in split:
|
||||
amount = split.count(tag_token)
|
||||
begin = 0
|
||||
end = 0
|
||||
for i in range(amount):
|
||||
begin = split.find(tag_token, end) + len(tag_token)
|
||||
end = split.find(a_token, begin)
|
||||
type_names.append(split[begin : end])
|
||||
break
|
||||
|
||||
# # # RELEASE YEAR
|
||||
|
||||
release_year = ''
|
||||
for split in info_splits:
|
||||
if 'Release Date:' in split:
|
||||
begin = split.find(tag_token, 0) + len(tag_token)
|
||||
end = split.find(a_token, 0)
|
||||
release_year = split[begin : end]
|
||||
break
|
||||
|
||||
# # # VOCALS
|
||||
|
||||
vocal_names = []
|
||||
for split in info_splits:
|
||||
if 'Vocals:' in split:
|
||||
amount = split.count(tag_token)
|
||||
begin = 0
|
||||
end = 0
|
||||
for i in range(amount):
|
||||
begin = split.find(tag_token, end) + len(tag_token)
|
||||
end = split.find(a_token, begin)
|
||||
vocal_names.append(split[begin : end])
|
||||
break
|
||||
|
||||
# # # PRODUCERS
|
||||
|
||||
producers_names = []
|
||||
for split in info_splits:
|
||||
if 'Producer:' in split:
|
||||
amount = split.count(tag_token)
|
||||
begin = 0
|
||||
end = 0
|
||||
for i in range(amount):
|
||||
begin = split.find(tag_token, end) + len(tag_token)
|
||||
end = split.find(a_token, begin)
|
||||
producers_names.append(split[begin : end])
|
||||
break
|
||||
|
||||
# # # GENRES
|
||||
|
||||
genres_names = []
|
||||
for split in info_splits:
|
||||
if 'Genre:' in split:
|
||||
amount = split.count(tag_token)
|
||||
begin = 0
|
||||
end = 0
|
||||
for i in range(amount):
|
||||
begin = split.find(tag_token, end) + len(tag_token)
|
||||
end = split.find(a_token, begin)
|
||||
genres_names.append(split[begin : end])
|
||||
break
|
||||
|
||||
# # # LINKS
|
||||
|
||||
links = []
|
||||
for split in info_splits:
|
||||
if 'Official site' in split:
|
||||
amount = split.count(href_token)
|
||||
begin = 0
|
||||
end = 0
|
||||
for i in range(amount):
|
||||
begin = split.find(href_token, end) + len(href_token)
|
||||
end = split.find(href_end_token, begin)
|
||||
links.append(split[begin : end])
|
||||
break
|
||||
|
||||
print(album_title)
|
||||
print('--------')
|
||||
print(alternative_name)
|
||||
print(type_names)
|
||||
print(vocal_names)
|
||||
print(producers_names)
|
||||
print(genres_names)
|
||||
print(release_year)
|
||||
print(links)
|
||||
print(image_url)
|
||||
|
||||
# SEARCHING FOR YOUTUBE URL
|
||||
|
||||
youtube_url = ''
|
||||
|
||||
video_page_splits = str(soup).split('\n')
|
||||
for split in video_page_splits:
|
||||
if 'youtube' in split:
|
||||
begin = split.find('src="', 0) + len('src="')
|
||||
end = split.find('"', begin)
|
||||
youtube_url = split[begin : end]
|
||||
|
||||
# SEARCHING FOR VOCADB URL
|
||||
|
||||
vocadb_url = ""
|
||||
entry_content_soup = soup.findAll('div', {'class': 'entry-content'})
|
||||
entry_content_splits = str(entry_content_soup).split('\n')
|
||||
for split in entry_content_splits:
|
||||
if 'vocadb.net' in split:
|
||||
begin = split.find('a href="', 0) + len('a href="')
|
||||
end = split.find('">Vo', 0)
|
||||
vocadb_url = split[begin : end]
|
||||
|
||||
# PARSING VOCADB PAGE
|
||||
|
||||
external_links = []
|
||||
vocadb_url = vocadb_url.replace('amp;', '')
|
||||
if len(vocadb_url) > 0:
|
||||
resp = requests.get(vocadb_url)
|
||||
soup = BeautifulSoup(resp.text, 'lxml')
|
||||
if len(soup.findAll('img', {'class': 'coverPic'})) > 0:
|
||||
vocadb_splits = str(soup).split('\n')
|
||||
for split in vocadb_splits:
|
||||
if 'www.nicovideo.jp/watch' in split and len(youtube_url) == 0:
|
||||
begin = split.find('href="', 0) + len('href="')
|
||||
end = split.find('">', begin)
|
||||
youtube_url = split[begin : end]
|
||||
if 'class="extLink"' in split and 'amazon' not in split:
|
||||
begin = split.find('href="', 0) + len('href="')
|
||||
end = split.find('" onclick', begin)
|
||||
external_links.append(split[begin : end])
|
||||
|
||||
print(external_links)
|
||||
print(youtube_url)
|
||||
|
||||
text = "ALBUM:\n" + album_title
|
||||
|
||||
if len(alternative_name) > 0:
|
||||
text += str('\n\nALTERNATIVE TITLES:\n' + alternative_name)
|
||||
|
||||
if len(type_names) > 0:
|
||||
text += '\n\nTYPE:\n'
|
||||
for type_name in type_names:
|
||||
text += (type_name + '; ')
|
||||
|
||||
if len(vocal_names) > 0:
|
||||
text += '\n\nVOCAL:\n'
|
||||
for vocal_name in vocal_names:
|
||||
text += (vocal_name + '; ')
|
||||
|
||||
if len(producers_names) > 0:
|
||||
text += '\n\nPRODUCING:\n'
|
||||
for producer_name in producers_names:
|
||||
text += (producer_name + '; ')
|
||||
|
||||
if len(genres_names) > 0:
|
||||
text += '\n\nGENRE:\n'
|
||||
for genre_name in genres_names:
|
||||
text += (genre_name + '; ')
|
||||
|
||||
if len(release_year) > 0:
|
||||
text += str('\n\nRELEASED:\n' + release_year)
|
||||
|
||||
if len(youtube_url) > 0:
|
||||
text += str('\n\nVIDEO: \n' + youtube_url)
|
||||
|
||||
text += str('\n\nMIKUDB: \n' + album_url)
|
||||
|
||||
if len(external_links) == 0:
|
||||
external_links = links
|
||||
|
||||
if len(external_links) > 0:
|
||||
text += '\n\nLINKS: \n'
|
||||
for external_link in external_links:
|
||||
text += (external_link + '\n\n')
|
||||
|
||||
mastodon = Mastodon(
|
||||
access_token = 'token.dat',
|
||||
api_base_url = 'https://your.site/'
|
||||
)
|
||||
|
||||
fformat = op.splitext(image_url)[1][1:]
|
||||
if (fformat == 'jpg'):
|
||||
fformat = 'jpeg'
|
||||
|
||||
image_media = mastodon.media_post(requests.get(image_url).content, f'image/{fformat}')
|
||||
|
||||
mastodon.status_post(text, media_ids=[image_media], visibility='unlisted', sensitive=False)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
|
@ -0,0 +1 @@
|
|||
token.dat
|
|
@ -0,0 +1,39 @@
|
|||
import sys
|
||||
import os.path as op
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
from mastodon import Mastodon
|
||||
|
||||
URL_HEAD = 'https://anime-pictures.net'
|
||||
|
||||
def main():
|
||||
# Searching for the url of the highest rated art
|
||||
resp = requests.get(URL_HEAD)
|
||||
soup = BeautifulSoup(resp.text, 'lxml')
|
||||
final_url = URL_HEAD + str(soup.findAll('span', {'class': 'img_block2'})[12]).split('"')[5]
|
||||
print(final_url)
|
||||
|
||||
# Requesting its page and getting the actual full image
|
||||
resp = requests.get(final_url)
|
||||
soup = BeautifulSoup(resp.text, 'lxml')
|
||||
src_url = URL_HEAD + str(soup.find('div', {'id': 'big_preview_cont'})).split('"')[5]
|
||||
|
||||
src_ext = src_url.split('.')[-1]
|
||||
if src_ext == 'jpg':
|
||||
src_ext = 'jpeg'
|
||||
|
||||
# Logging in and posting
|
||||
mastodon = Mastodon(
|
||||
access_token = 'token.dat',
|
||||
api_base_url = 'https://your.site/'
|
||||
)
|
||||
|
||||
media = mastodon.media_post(requests.get(src_url).content, 'image/' + src_ext)
|
||||
toot = ':senko:\nurl: ' + final_url
|
||||
|
||||
mastodon.status_post(toot, media_ids=[media], visibility='unlisted', sensitive=False)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
Loading…
Reference in New Issue