Compare commits
3 Commits
d382aac549
...
76185a2ba4
Author | SHA1 | Date | |
---|---|---|---|
76185a2ba4 | |||
0e82467772 | |||
e84c82067d |
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@
|
|||||||
/rsc*/
|
/rsc*/
|
||||||
/md5/
|
/md5/
|
||||||
/src/cfg*.py
|
/src/cfg*.py
|
||||||
|
/log.txt
|
||||||
|
|
||||||
# Virtual environment
|
# Virtual environment
|
||||||
/venv*
|
/venv*
|
||||||
|
46
cron.sh
Executable file
46
cron.sh
Executable file
@ -0,0 +1,46 @@
|
|||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
# Yandere Lewd Bot, an image posting bot for Pleroma
|
||||||
|
# Copyright (C) 2022 Anon <yanderefedi@proton.me>
|
||||||
|
#
|
||||||
|
# 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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# WARNING: This script has not been thoroughly tested. Use at your own risk.
|
||||||
|
|
||||||
|
# Get the runtime path of the bot
|
||||||
|
ABS_PATH="$(readlink -f "$0")"
|
||||||
|
RUN_DIR="$(dirname "$ABS_PATH")"
|
||||||
|
|
||||||
|
# Relative paths to the entry point and log file
|
||||||
|
# Make sure the relative path is the same as the absolute path in your cron file
|
||||||
|
LOG='./log.txt'
|
||||||
|
ENTRY='./run.sh'
|
||||||
|
|
||||||
|
# cd into the bot's root path, set up the virtual environment, and run
|
||||||
|
cd "$RUN_DIR"
|
||||||
|
[ ! -f "$ENTRY" ] && echo "Cannot find entry: ${ENTRY}" && cd - > /dev/null && exit 1
|
||||||
|
if [ ! -f "$LOG" ]; then
|
||||||
|
"$ENTRY"
|
||||||
|
else
|
||||||
|
INDEX="$(expr `grep "^Profile" "$LOG" | cut -d ' ' -f5 | tail -n 1` + 1)"
|
||||||
|
STATE="$(grep "^State" "$LOG" | cut -d ' ' -f2 | tail -n 1 | awk -F ',' "{sub(\$${INDEX},\$${INDEX}+1,\$${INDEX})}7" | tr ' ' ',')"
|
||||||
|
"$ENTRY" -i "$INDEX" -s "$STATE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
RETURN_CODE="$?"
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
cd - > /dev/null
|
||||||
|
|
||||||
|
exit "$RETURN_CODE"
|
@ -98,6 +98,7 @@ settings_backend = {
|
|||||||
"url": "https://danbooru.donmai.us"
|
"url": "https://danbooru.donmai.us"
|
||||||
},
|
},
|
||||||
# The below backends are still being tested
|
# The below backends are still being tested
|
||||||
|
# Use at your own risk
|
||||||
"konachan_backend": {
|
"konachan_backend": {
|
||||||
"module": "konachan_backend",
|
"module": "konachan_backend",
|
||||||
"username": None,
|
"username": None,
|
||||||
@ -120,7 +121,8 @@ settings_backend = {
|
|||||||
|
|
||||||
|
|
||||||
# Apply post settings
|
# Apply post settings
|
||||||
|
# Post settings consist of a 2d matrix with both the x and y axis increased per post
|
||||||
settings_post = (
|
settings_post = (
|
||||||
setup_profile("danbooru.random", "danbooru_backend", banned_tags, ("random",), "#random", "#random #nsfw #lewd"),
|
(setup_profile("danbooru.random", "danbooru_backend", banned_tags, ("random",), "#random", "#random #nsfw #lewd"),),
|
||||||
setup_profile("danbooru.yandere", "danbooru_backend", banned_tags, ("yandere",), "#yandere", "#yandere #nsfw #lewd"),
|
(setup_profile("danbooru.yandere", "danbooru_backend", banned_tags, ("yandere",), "#yandere", "#yandere #nsfw #lewd"),)
|
||||||
)
|
)
|
||||||
|
@ -42,7 +42,8 @@ def main():
|
|||||||
parser.add_argument("--debug", help="Same as --dry-run", action="store_true")
|
parser.add_argument("--debug", help="Same as --dry-run", action="store_true")
|
||||||
parser.add_argument("-c", "--config", help="Set custom config file (Default: {})".format(default_cfg), default=default_cfg)
|
parser.add_argument("-c", "--config", help="Set custom config file (Default: {})".format(default_cfg), default=default_cfg)
|
||||||
parser.add_argument("-k", "--keyfile", help="Keyfile used for decryption")
|
parser.add_argument("-k", "--keyfile", help="Keyfile used for decryption")
|
||||||
parser.add_argument("-i", "--index", help="Start at index (only matters if profile is set to sequential", default=0)
|
parser.add_argument("-i", "--index", help="Start at index (only matters if profile is set to sequential)", default=0)
|
||||||
|
parser.add_argument("-s", "--state", help="Set comma seperated state (only matters if profile is set to sequential)", default=None)
|
||||||
parser.add_argument("remainder", help=argparse.SUPPRESS, nargs=argparse.REMAINDER)
|
parser.add_argument("remainder", help=argparse.SUPPRESS, nargs=argparse.REMAINDER)
|
||||||
arguments = parser.parse_args()
|
arguments = parser.parse_args()
|
||||||
|
|
||||||
@ -67,6 +68,12 @@ def main():
|
|||||||
)
|
)
|
||||||
|
|
||||||
yandere.currentIndexCount = int(arguments.index)
|
yandere.currentIndexCount = int(arguments.index)
|
||||||
|
if arguments.state:
|
||||||
|
state = arguments.state.split(",")
|
||||||
|
if len(state) != len(yandere_config.settings_post):
|
||||||
|
print("State length does not match profile length. Ignoring...")
|
||||||
|
else:
|
||||||
|
yandere.currentProfileIndex = list(map(int, state))
|
||||||
|
|
||||||
# Setup exit calls
|
# Setup exit calls
|
||||||
# Must be done after we declare our bot(s), otherwise this will be called if quitting on decrypting settings )
|
# Must be done after we declare our bot(s), otherwise this will be called if quitting on decrypting settings )
|
||||||
|
@ -24,6 +24,7 @@ import shutil
|
|||||||
import importlib
|
import importlib
|
||||||
import magic
|
import magic
|
||||||
import random
|
import random
|
||||||
|
import copy
|
||||||
from threading import Event
|
from threading import Event
|
||||||
from mastodon import Mastodon, MastodonIllegalArgumentError, MastodonAPIError, MastodonVersionError
|
from mastodon import Mastodon, MastodonIllegalArgumentError, MastodonAPIError, MastodonVersionError
|
||||||
|
|
||||||
@ -49,6 +50,7 @@ class YandereBot:
|
|||||||
consecutive_failed_uploads = 0
|
consecutive_failed_uploads = 0
|
||||||
currentSessionCount = 0
|
currentSessionCount = 0
|
||||||
currentIndexCount = 0
|
currentIndexCount = 0
|
||||||
|
currentProfileIndex = tuple()
|
||||||
debug_mode = False
|
debug_mode = False
|
||||||
primed = False
|
primed = False
|
||||||
decrypted = False
|
decrypted = False
|
||||||
@ -62,6 +64,7 @@ class YandereBot:
|
|||||||
self.load_settings(self.cfg)
|
self.load_settings(self.cfg)
|
||||||
self.debug_mode = debug_mode or self.settings_behavior["debug"]
|
self.debug_mode = debug_mode or self.settings_behavior["debug"]
|
||||||
self.settings_encrypt["keyfile"] = keyfile or self.settings_encrypt["keyfile"]
|
self.settings_encrypt["keyfile"] = keyfile or self.settings_encrypt["keyfile"]
|
||||||
|
self.currentProfileIndex = [0]*len(self.settings_post)
|
||||||
random.seed(os.urandom(16))
|
random.seed(os.urandom(16))
|
||||||
if prime_bot:
|
if prime_bot:
|
||||||
self.prime_bot()
|
self.prime_bot()
|
||||||
@ -125,11 +128,18 @@ class YandereBot:
|
|||||||
url = picked["file_url"] if picked else None
|
url = picked["file_url"] if picked else None
|
||||||
path = picked["full_path"] if picked else None
|
path = picked["full_path"] if picked else None
|
||||||
nsfw = picked["nsfw"] if picked else None
|
nsfw = picked["nsfw"] if picked else None
|
||||||
index = (self.currentIndexCount - int(self.currentSessionCount > 0)) % len(self.settings_post)
|
|
||||||
|
posted_once = int(self.currentSessionCount > 0)
|
||||||
|
index = (self.currentIndexCount - posted_once) % len(self.settings_post)
|
||||||
|
state_print = copy.copy(self.currentProfileIndex)
|
||||||
|
state_print[index] = state_print[index] - posted_once
|
||||||
|
|
||||||
|
state_print = [state_print[i] % len(self.settings_post[i]) for i in range(0, len(self.currentProfileIndex))]
|
||||||
|
|
||||||
print("Profile: {} | Index: {} | NSFW: {} | Path: {} | URL: {}".format(
|
print("Profile: {} | Index: {} | NSFW: {} | Path: {} | URL: {}".format(
|
||||||
profile, index, nsfw, path, url
|
profile, index, nsfw, path, url
|
||||||
))
|
))
|
||||||
|
print("State: {}".format(','.join(map(str, state_print))))
|
||||||
|
|
||||||
# Returns a list of media paths (without the hashes)
|
# Returns a list of media paths (without the hashes)
|
||||||
def download_media(self, picked_profile):
|
def download_media(self, picked_profile):
|
||||||
@ -235,15 +245,22 @@ class YandereBot:
|
|||||||
return picked
|
return picked
|
||||||
|
|
||||||
|
|
||||||
|
def pick_index(self, mode, current_index, length):
|
||||||
|
if mode == "random":
|
||||||
|
return random.randint(0, length - 1)
|
||||||
|
elif mode == "sequential":
|
||||||
|
return current_index % length
|
||||||
|
|
||||||
|
|
||||||
def pick_profile(self):
|
def pick_profile(self):
|
||||||
profiles = self.settings_post
|
# Get x and y
|
||||||
tag_select = self.settings_behavior["tag_select"].lower()
|
mode = self.settings_behavior["tag_select"].lower()
|
||||||
pick_index = None
|
posts = self.settings_post
|
||||||
if tag_select == "random":
|
x = self.pick_index(mode, self.currentIndexCount, len(posts))
|
||||||
pick_index = random.randint(0, len(profiles) - 1)
|
y = self.pick_index(mode, self.currentProfileIndex[x], len(posts[x]))
|
||||||
elif tag_select == "sequential":
|
|
||||||
pick_index = self.currentIndexCount % len(profiles)
|
# Return the Profile
|
||||||
return profiles[pick_index]
|
return x, y
|
||||||
|
|
||||||
|
|
||||||
# The main post function
|
# The main post function
|
||||||
@ -260,7 +277,8 @@ class YandereBot:
|
|||||||
# Attempt post
|
# Attempt post
|
||||||
try:
|
try:
|
||||||
# Post
|
# Post
|
||||||
picked_profile = self.pick_profile()
|
x, y = self.pick_profile()
|
||||||
|
picked_profile = self.settings_post[x][y]
|
||||||
picked = self.download_media(picked_profile)
|
picked = self.download_media(picked_profile)
|
||||||
self._post(picked)
|
self._post(picked)
|
||||||
|
|
||||||
@ -269,6 +287,9 @@ class YandereBot:
|
|||||||
# After a successful post
|
# After a successful post
|
||||||
self.currentSessionCount += 1
|
self.currentSessionCount += 1
|
||||||
self.consecutive_failed_uploads = 0
|
self.consecutive_failed_uploads = 0
|
||||||
|
|
||||||
|
# Set indexes
|
||||||
|
self.currentProfileIndex[x] += 1
|
||||||
self.currentIndexCount += 1
|
self.currentIndexCount += 1
|
||||||
|
|
||||||
# The post was successful
|
# The post was successful
|
||||||
@ -362,7 +383,3 @@ class FailedLogin(Exception):
|
|||||||
|
|
||||||
class BadCfgFile(Exception):
|
class BadCfgFile(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class MissingMasterList(Exception):
|
|
||||||
pass
|
|
||||||
|
Reference in New Issue
Block a user