commit 1a402b9a6499ebfa61eb0c5ae8aef7883005f2b5 Author: NaiJi Date: Mon Jan 18 19:28:44 2021 +0300 Init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3d85d67 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +token.dat diff --git a/post.py b/post.py new file mode 100644 index 0000000..88f7671 --- /dev/null +++ b/post.py @@ -0,0 +1,90 @@ +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, 1640, 2600, 84, 156, 162, 897, 214, 391, 98, 2047, 1341, 83] + +def main(): + #Logging into VNDB + vndb = v.VNDB('VNDBbot', '0.1', 'LOGIN', 'PASSWORD') + id = -1 + + 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 < 2: + 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'] != 0) or (vn_details['image_flagging']['violence_avg'] != 0): + continue + + # 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 '' + raw_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) + + # processing description and removing markdown + description = re.sub('^\[.rom.*\[\/url\]\].*', '', raw_description) + + # logging in and posting + mastodon = Mastodon( + access_token = 'token.dat', + api_base_url = 'https://udongein.xyz/' + ) + + text = title + '\n- - - - - - - -\n\n' + description + '\n\nReleased: ' + released + '\nPopularity: ' + (str(popularity) if popularity > -1 else 'unknown') + '\nRating:' + str(rating) + '\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 = [ ] + 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')) + + mastodon.status_post(text, media_ids=screens, visibility='unlisted', sensitive=False) + break + +if __name__ == '__main__': + sys.exit(main()) \ No newline at end of file diff --git a/vndb.py b/vndb.py new file mode 100644 index 0000000..0d990bf --- /dev/null +++ b/vndb.py @@ -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 . +""" + +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()