mirror of
https://github.com/migatu/conjurer.git
synced 2026-07-14 21:38:38 +00:00
Compare commits
91 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fe81f5e8fc | |||
| 6d51412ea3 | |||
| 382cf5d501 | |||
| e121c6dc39 | |||
| 548496e0a6 | |||
| 99409f7c0b | |||
| fd1107cd1b | |||
| f08ce02e85 | |||
| 78346d8448 | |||
| c780308541 | |||
| cc0af0ce32 | |||
| 99e3dd7dca | |||
| 16ead67cf3 | |||
| 5ca73d6ac9 | |||
| f3e690f395 | |||
| 8293b3a69c | |||
| 0ac9006665 | |||
| d912d9bc1b | |||
| b08642dd88 | |||
| 8b1950823b | |||
| 6589b73329 | |||
| 89003c32c9 | |||
| 17eace3e73 | |||
| 3f2248336d | |||
| f8664c0fd1 | |||
| 82273df13c | |||
| ae0d807714 | |||
| edc0a4a502 | |||
| 39ecb82395 | |||
| d8f5bd1805 | |||
| 3f68c6aaed | |||
| aee53de258 | |||
| 20caa5600a | |||
| 4a4f8df06e | |||
| 6c9f01971a | |||
| 211c45891e | |||
| de3d6a8f42 | |||
| 9c027fd636 | |||
| 9af6b8e187 | |||
| d00ede6c62 | |||
| 5b7d7b31b2 | |||
| 00172920a9 | |||
| 5e3ffdacb5 | |||
| 471d4e923b | |||
| d11f5d8d24 | |||
| cfb26d95a4 | |||
| 5e14299fef | |||
| 126de9a4a4 | |||
| 0d132983fc | |||
| 67cae0e68e | |||
| eabd0e8e1e | |||
| f7c91e3874 | |||
| c224b2ccc8 | |||
| 3ca9f2c6f3 | |||
| c52d55e0a2 | |||
| e1fa15abb3 | |||
| 74c76e639d | |||
| 35a65e48e9 | |||
| 5d5c136b41 | |||
| b9fbc0f910 | |||
| fd742c8f1c | |||
| 1c240342c5 | |||
| 7bd0c0aca4 | |||
| 7c8ad99743 | |||
| 90896fa9be | |||
| e3bec6bc11 | |||
| aa00045dec | |||
| 06e3671ec2 | |||
| 0879796cc6 | |||
| 9f756b3092 | |||
| 579a3f2a52 | |||
| 5505022dbb | |||
| d2e5a34b87 | |||
| c7696fafdc | |||
| 7f3de2ea13 | |||
| ec505f050f | |||
| f55c4ce1a7 | |||
| 432abc73b9 | |||
| cdaf2589b3 | |||
| 67ab3b4bba | |||
| 71623d9812 | |||
| ce54233908 | |||
| b0df66c5da | |||
| fda2733600 | |||
| 027050a4dd | |||
| b22b9add15 | |||
| 1fd5b8cfac | |||
| 5e3d90c038 | |||
| fef53a3587 | |||
| be1e338e54 | |||
| d6dd276a92 |
+2
-1
@@ -2,7 +2,8 @@
|
||||
*logs
|
||||
*actions
|
||||
*notifications
|
||||
*tools
|
||||
plugins
|
||||
user_trunk.yaml
|
||||
user.yaml
|
||||
tools
|
||||
tmp
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[settings]
|
||||
profile=black
|
||||
@@ -2,9 +2,6 @@ rules:
|
||||
quoted-strings:
|
||||
required: only-when-needed
|
||||
extra-allowed: ["{|}"]
|
||||
empty-values:
|
||||
forbid-in-block-mappings: true
|
||||
forbid-in-flow-mappings: true
|
||||
key-duplicates: {}
|
||||
octal-values:
|
||||
forbid-implicit-octal: true
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# Generic, formatter-friendly config.
|
||||
select = ["B", "D3", "E", "F"]
|
||||
|
||||
# Never enforce `E501` (line length violations). This should be handled by formatters.
|
||||
ignore = ["E501"]
|
||||
+23
-30
@@ -1,43 +1,36 @@
|
||||
# This file controls the behavior of Trunk: https://docs.trunk.io/cli
|
||||
# To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml
|
||||
version: 0.1
|
||||
cli:
|
||||
version: 1.12.3
|
||||
version: 1.20.1
|
||||
# Trunk provides extensibility via plugins. (https://docs.trunk.io/plugins)
|
||||
plugins:
|
||||
sources:
|
||||
- id: trunk
|
||||
ref: v0.0.22
|
||||
ref: v1.4.5
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
lint:
|
||||
enabled:
|
||||
- checkov@2.3.75
|
||||
- yamllint@1.26.3
|
||||
- actionlint@1.6.25
|
||||
- markdownlint@0.35.0
|
||||
- trivy@0.43.1
|
||||
- trufflehog@3.44.0
|
||||
- pylint
|
||||
- codespell
|
||||
- cspell
|
||||
- git-diff-check
|
||||
- eslint
|
||||
- prettier
|
||||
- semgrep
|
||||
- autopep8
|
||||
- bandit
|
||||
- black
|
||||
- flake8
|
||||
- isort
|
||||
- mypy
|
||||
- pylint
|
||||
- ruff
|
||||
- semgrep
|
||||
- yapf
|
||||
- gitleaks
|
||||
|
||||
# Many linters and tools depend on runtimes - configure them here. (https://docs.trunk.io/runtimes)
|
||||
runtimes:
|
||||
enabled:
|
||||
- go@1.19.5
|
||||
- node@18.12.1
|
||||
- python@3.10.8
|
||||
# This is the section where you manage your linters. (https://docs.trunk.io/check/configuration)
|
||||
lint:
|
||||
enabled:
|
||||
- actionlint@1.6.27
|
||||
- bandit@1.7.8
|
||||
- black@24.3.0
|
||||
- codespell
|
||||
- checkov@3.2.48
|
||||
- git-diff-check
|
||||
- isort@5.13.2
|
||||
- pylint
|
||||
- markdownlint@0.39.0
|
||||
- prettier@3.2.5
|
||||
- ruff@0.3.4
|
||||
- trivy@0.50.1
|
||||
- trufflehog@3.71.0
|
||||
- yamllint@1.35.1
|
||||
actions:
|
||||
disabled:
|
||||
- trunk-announce
|
||||
|
||||
Vendored
-2
@@ -1,6 +1,4 @@
|
||||
{
|
||||
"python.linting.enabled": true,
|
||||
"python.linting.pylintEnabled": true,
|
||||
"trunk.inlineDecorators": true,
|
||||
"trunk.inlineDecoratorsForAllExtensions": true,
|
||||
"trunk.showPreexistingIssues": true,
|
||||
|
||||
+1707
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,122 @@
|
||||
import logging
|
||||
import threading
|
||||
import json
|
||||
import time
|
||||
from queue import Queue, Empty
|
||||
from flask import Flask, jsonify, request
|
||||
from waitress import serve
|
||||
|
||||
HOST_ADDRESS = "192.168.1.191"
|
||||
PORT_ADDRESS = 5000
|
||||
OUT_COMM_Q = Queue()
|
||||
IN_COMM_Q = Queue()
|
||||
awaiting_q = []
|
||||
incoming_q = Queue()
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/conjurer", methods=["POST"])
|
||||
def answer_external_command():
|
||||
"""
|
||||
The function `answer_external_command` logs the request data, loads the data as JSON, logs the
|
||||
record, and then puts the record into an incoming queue before returning a success message.
|
||||
:return: The function `answer_external_command()` is returning a JSON response with the message
|
||||
"SUCCESS".
|
||||
"""
|
||||
app.logger.info(request)
|
||||
record = json.loads(request.data)
|
||||
app.logger.info(record)
|
||||
app.logger.info("DATA RECEIVED")
|
||||
incoming_q.put(record)
|
||||
return jsonify("SUCCESS")
|
||||
|
||||
@app.route("/conjurer", methods=["GET"])
|
||||
def check_alive():
|
||||
"""
|
||||
The function "check_alive" returns a JSON response with the message "ALIVE" when the "/conjurer"
|
||||
route is accessed via a GET request.
|
||||
:return: The code snippet is a Flask route that listens for GET requests to the "/conjurer"
|
||||
endpoint. When a GET request is made to this endpoint, the function check_alive() is called, which
|
||||
returns a JSON response with the message "ALIVE".
|
||||
"""
|
||||
return jsonify("ALIVE")
|
||||
|
||||
def flask_debug(_logger):
|
||||
"""
|
||||
The `flask_debug` function starts a Flask application in debug mode without using the reloader.
|
||||
Do not use for production for fucks sake.
|
||||
"""
|
||||
_logger.info("Attempt debug")
|
||||
# trunk-ignore(bandit/B201)
|
||||
app.run(debug=True, use_reloader=False, host=HOST_ADDRESS, port=PORT_ADDRESS)
|
||||
|
||||
|
||||
def waitress_run(_logger):
|
||||
"""
|
||||
The `waitress_run` function serves the `app` on host "0.0.0.0"
|
||||
and port 5000 using the Waitress WSGI server.
|
||||
"""
|
||||
_logger.info("Attempt waitress")
|
||||
serve(app, host=HOST_ADDRESS, port=PORT_ADDRESS)
|
||||
|
||||
def scan_queue(_logger):
|
||||
"""
|
||||
The function `scan_queue` reads data from a queue, logs it, and appends it to another queue.
|
||||
|
||||
:param _logger: The `_logger` parameter is typically an instance of a logging object that is used to
|
||||
record and store log messages. It is commonly used to track the flow of the program, record errors,
|
||||
and provide information for debugging purposes. In this code snippet, the `_logger` object is used
|
||||
to log the
|
||||
"""
|
||||
while True:
|
||||
data = OUT_COMM_Q.get()
|
||||
_logger.info(data)
|
||||
awaiting_q.append(data)
|
||||
|
||||
def scan_incoming(_logger):
|
||||
"""
|
||||
The `scan_incoming` function continuously checks for incoming data, processes it, and logs when data
|
||||
is found.
|
||||
|
||||
:param _logger: The `_logger` parameter in the `scan_incoming` function is a logger object that is
|
||||
used to log messages or information during the execution of the function. It is typically used for
|
||||
debugging, monitoring, or tracking the flow of the program. In this case, the `_logger` is being
|
||||
used
|
||||
"""
|
||||
while True:
|
||||
try:
|
||||
answer = incoming_q.get(block=False)
|
||||
_logger.info("DATA FOUND")
|
||||
for record in awaiting_q:
|
||||
if record.uuid in answer.keys():
|
||||
record.stop = True
|
||||
record.entries = answer[record.uuid]
|
||||
IN_COMM_Q.put(record)
|
||||
except Empty:
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def comm_subroutine(logger):
|
||||
"""
|
||||
The `comm_subroutine` function starts multiple threads to run different tasks concurrently.
|
||||
|
||||
:param logger: The `logger` parameter in the `comm_subroutine` function is an instance of a logger
|
||||
object that is used for logging messages at various levels (e.g., debug, info, warning, error). In
|
||||
the provided code snippet, the logger is used to log messages at the "info" level
|
||||
"""
|
||||
#logger.setLevel(logging.DEBUG)
|
||||
logger.info("Started")
|
||||
threads = []
|
||||
#threads.append(threading.Thread(target=flask_debug, args=(logger,)))
|
||||
threads.append(threading.Thread(target=waitress_run, args=(logger,)))
|
||||
threads.append(threading.Thread(target=scan_queue,args=(logger,)))
|
||||
threads.append(threading.Thread(target=scan_incoming,args=(logger,)))
|
||||
|
||||
|
||||
for worker in threads:
|
||||
worker.start()
|
||||
for worker in threads:
|
||||
worker.join()
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging_client = logging.getLogger(__name__)
|
||||
comm_subroutine(logging_client)
|
||||
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Conjurer
|
||||
After=multi-user.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/home/pi/Conjurer/env/bin/python3 /home/pi/Conjurer/bot.py
|
||||
Restart=on-abort
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,343 @@
|
||||
from logging import handlers
|
||||
import re
|
||||
import logging
|
||||
import threading
|
||||
import time
|
||||
from flask import Flask, jsonify, request
|
||||
import netrc
|
||||
import json
|
||||
import asyncio
|
||||
from json.decoder import JSONDecodeError
|
||||
from urllib.request import urlopen
|
||||
from habanero import Crossref
|
||||
from waitress import serve
|
||||
from queue import Queue
|
||||
import search_bot
|
||||
import scrape_bot
|
||||
import requests
|
||||
NETRC_FILE = r"C:\Users\Activcom.pl\.netrc"
|
||||
|
||||
HOST_ADDRESS = "192.168.1.192"
|
||||
PORT_ADDRESS = 5001
|
||||
MAIN_BOT_ADDRESS = "http://192.168.1.191:5000"
|
||||
SEND_RESULTS = "/conjurer"
|
||||
BDSM_UUID_TEST = '96b7f85a-1142-4908-8986-62a2ea25a147'
|
||||
MAX_CR_RESULTS = 150000
|
||||
ENCODING = "utf-8"
|
||||
app = Flask(__name__)
|
||||
|
||||
librarian_queue = Queue()
|
||||
librarian_list = []
|
||||
|
||||
class Librarian(object):
|
||||
|
||||
def __init__(self, app, query, uuid) -> None:
|
||||
netrc_mod = netrc.netrc(NETRC_FILE)
|
||||
authTokens = netrc_mod.authenticators("crossref")
|
||||
self.cr = Crossref(mailto=authTokens[0])
|
||||
self.query = query
|
||||
self.uuid = str(uuid)
|
||||
self.limit = MAX_CR_RESULTS
|
||||
self.fetched = 0
|
||||
self.hit = 0
|
||||
self.total = 0
|
||||
self.app = app
|
||||
self.live_results = []
|
||||
self.final_result = []
|
||||
self.not_in_db = []
|
||||
self.search_result_from_cr = {}
|
||||
self.done = False
|
||||
|
||||
async def search_crossref(self, query):
|
||||
self.app.logger.info("STARTED SEARCH")
|
||||
result = self.cr.works(query = query, limit = 1000)
|
||||
self.search_result_from_cr.update(result)
|
||||
self.total = result['message']['total-results']
|
||||
self.fetched += len(result['message']['items'])
|
||||
self.app.logger.info (self.total)
|
||||
self.app.logger.info(self.fetched)
|
||||
while self.total > self.fetched and self.limit > self.fetched:
|
||||
result = self.cr.works(query = query, limit = 1000)
|
||||
self.search_result_from_cr.update(result)
|
||||
self.total = result['message']['total-results']
|
||||
self.fetched += len(result['message']['items'])
|
||||
self.app.logger.info (self.total)
|
||||
self.app.logger.info(self.fetched)
|
||||
time.sleep(0.1)
|
||||
self.app.logger.info("CROSSREF DONE")
|
||||
#TODO: add to sql with UUID
|
||||
#sql row - title, doi, author, uuid, last retrieved, is_available
|
||||
|
||||
with open("rr_results.json", "r+", encoding="utf-8") as data_file:
|
||||
# First we load existing data into a dict.
|
||||
try:
|
||||
file_data = json.load(data_file)
|
||||
except JSONDecodeError:
|
||||
file_data = {}
|
||||
summarized_results = []
|
||||
self.app.logger.info("REFINE: Removing all derived works from the list")
|
||||
for item in self.search_result_from_cr['message']['items']:
|
||||
container = "NO"
|
||||
if "container-title" in item:
|
||||
container = "YES"
|
||||
else:
|
||||
summarized_results.append({"DOI" : item['DOI'], "title": item['title'] if 'title' in item else None,"type": item['type'] if 'type' in item else None, "container": container})
|
||||
result = {self.uuid : {"total_results": self.search_result_from_cr['message']['total-results'], "on_page" : 1, "summary":summarized_results, "results":self.search_result_from_cr['message']['items']}}
|
||||
if file_data:
|
||||
file_data.update(result)
|
||||
else:
|
||||
file_data = result
|
||||
|
||||
self.app.logger.info("REFINE: Dumping to file")
|
||||
data_file.truncate(0)
|
||||
data_file.seek(0)
|
||||
json.dump(file_data, data_file, indent=4)
|
||||
return result
|
||||
|
||||
async def check_dois_in_local_db(self, doi):
|
||||
self.app.logger.info("REFINE: Running search in the backend app")
|
||||
coro = asyncio.to_thread(search_bot.search_for_doi, doi, self.live_results, self.app.logger)
|
||||
result = await coro
|
||||
return result
|
||||
|
||||
async def check_if_exists_brute_force(self, page_url):
|
||||
self.app.logger.error("REFINE: Brute force search!")
|
||||
if not page_url.startswith(("http:", "https:")):
|
||||
raise ValueError("URL must start with 'http:' or 'https:'")
|
||||
# trunk-ignore(bandit/B310)
|
||||
with urlopen(page_url) as response:
|
||||
data = response.read()
|
||||
text = data.decode("utf-8")
|
||||
for line in text.splitlines():
|
||||
if re.match(r".*Unfortunately, Sci-Hub doesn't have the requested document.*", line):
|
||||
return False
|
||||
if m := re.match(r".*<embed type=\"application.pdf\"\s*src=\"(.*\.pdf)",line):
|
||||
direct_download_link = "https:" + str(m.group(1))
|
||||
self.app.logger.info (direct_download_link)
|
||||
return True
|
||||
return False
|
||||
|
||||
async def check_if_exists(self, doi, brute_force = False):
|
||||
result = {}
|
||||
result = await self.check_dois_in_local_db(doi)
|
||||
if brute_force and not result:
|
||||
for item in doi:
|
||||
item_link = "https://sci-hub.se/" + item[0]
|
||||
tmp = {"DOI" : item["DOI"], "exists" : await self.check_if_exists_brute_force(item_link), "data": item}
|
||||
result.update(tmp)
|
||||
return result
|
||||
|
||||
async def refine_query(self, unrefined_reqult, brute_force = False):
|
||||
temp = []
|
||||
refined_result = []
|
||||
for key in unrefined_reqult:
|
||||
self.app.logger.info("KEY:")
|
||||
self.app.logger.info(key)
|
||||
|
||||
for item in unrefined_reqult[self.uuid]["summary"]:
|
||||
if item["container"] == "NO" and item["title"]:
|
||||
refined_result.append(item)
|
||||
|
||||
for item in refined_result:
|
||||
temp.append([item["DOI"], item])
|
||||
|
||||
refined_result = await self.check_if_exists(temp)
|
||||
|
||||
for item in refined_result:
|
||||
if item["exists"]:
|
||||
self.final_result.append(item["data"])
|
||||
else:
|
||||
self.not_in_db.append(item["data"])
|
||||
self.hit = len(self.final_result)
|
||||
return self.final_result
|
||||
#TODO: DOłożyć sprawdzenie czy w rafinowanym pliku już nie mamy częściowego wyniku
|
||||
async def answer_query(self):
|
||||
#TODO: DOłożyć sprawdzenie czy w rafinowanym pliku już nie mamy częściowego wyniku tutaj bo zanim w ogóle otworzymy nierafinowany
|
||||
#Search sql for UUID
|
||||
#SQL SELECT * FROM RESULTS WHERE UUID = uuid
|
||||
self.app.logger.info(f"Search started {self.uuid}")
|
||||
database = None
|
||||
query = self.query
|
||||
with open("cr_results.json", "r+", encoding="utf-8") as cr_file:
|
||||
#tu logika komunikacji z SQL i cała logika związana z wyszukaniem
|
||||
#ale tymczasowo plik
|
||||
try:
|
||||
database = json.load(cr_file)
|
||||
except JSONDecodeError:
|
||||
pass
|
||||
#TODO: Zwracać i final_result i not_in_db. Not in db_do pliku - i do ręcznego przeglądania potem.
|
||||
if database:
|
||||
for item in database.keys():
|
||||
if item in self.uuid:
|
||||
self.result = await self.refine_query(database)
|
||||
temp = {}
|
||||
for item in self.result:
|
||||
temp[item['DOI']] = {"Title" : item['title'], "type": item['type']}
|
||||
self.result = temp
|
||||
temp2 = {}
|
||||
for item in self.not_in_db:
|
||||
temp2[item['DOI']] = {"Title" : item['title'], "type": item['type']}
|
||||
self.not_in_db = temp2
|
||||
return self.result
|
||||
answer = await self.search_crossref(query=query)
|
||||
database.update(answer)
|
||||
cr_file.truncate(0)
|
||||
cr_file.seek(0)
|
||||
json.dump(database,cr_file)
|
||||
self.result = await self.refine_query(answer)
|
||||
else:
|
||||
answer = await self.search_crossref(query=query)
|
||||
database = answer
|
||||
cr_file.truncate(0)
|
||||
cr_file.seek(0)
|
||||
json.dump(database,cr_file)
|
||||
self.result = await self.refine_query(answer)
|
||||
self.app.logger.info("Refined")
|
||||
self.done = True
|
||||
temp = {}
|
||||
for item in self.result:
|
||||
temp[item['DOI']] = {"Title" : item['title'], "type": item['type']}
|
||||
self.result = temp
|
||||
temp2 = {}
|
||||
for item in self.not_in_db:
|
||||
temp2[item['DOI']] = {"Title" : item['title'], "type": item['type']}
|
||||
self.not_in_db = temp2
|
||||
return self.result
|
||||
|
||||
#============================= FLASK INTERNALS===============================
|
||||
def flask_debug():
|
||||
"""
|
||||
The `flask_debug` function starts a Flask application in debug mode without using the reloader.
|
||||
Do not use for production for fucks sake.
|
||||
"""
|
||||
# trunk-ignore(bandit/B201)
|
||||
app.run(debug=True, use_reloader=False, host=HOST_ADDRESS, port=PORT_ADDRESS)
|
||||
|
||||
def waitress_run():
|
||||
"""
|
||||
The `waitress_run` function serves the `app` on host "0.0.0.0"
|
||||
and port 5000 using the Waitress WSGI server.
|
||||
"""
|
||||
serve(app, host=HOST_ADDRESS, port=PORT_ADDRESS)
|
||||
|
||||
class BackgroundTaskSearch(threading.Thread):
|
||||
def run(self):
|
||||
loop = asyncio.new_event_loop() # loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(self._run())
|
||||
loop.close()
|
||||
|
||||
async def _run(self):
|
||||
while True:
|
||||
database = None
|
||||
ndb_database = None
|
||||
librarian = librarian_queue.get()
|
||||
self.app.logger.info("STARTED")
|
||||
result = await librarian.answer_query()
|
||||
result = {librarian.uuid: result}
|
||||
self.app.logger.info("Saving to file")
|
||||
with open("not_in_db.json", "r+", encoding="utf-8") as ndb_file:
|
||||
try:
|
||||
ndb_database = json.load(ndb_file)
|
||||
except JSONDecodeError:
|
||||
pass
|
||||
if ndb_database:
|
||||
ndb_database.update(librarian.not_in_db)
|
||||
else:
|
||||
ndb_database = librarian.not_in_db
|
||||
ndb_file.truncate(0)
|
||||
ndb_file.seek(0)
|
||||
json.dump(ndb_database, ndb_file)
|
||||
|
||||
with open("s_results.json", "r+", encoding="utf-8") as s_file:
|
||||
try:
|
||||
database = json.load(s_file)
|
||||
except JSONDecodeError:
|
||||
pass
|
||||
if database:
|
||||
self.app.logger.info(database)
|
||||
self.app.logger.info(result)
|
||||
database.update(result)
|
||||
else:
|
||||
database = result
|
||||
self.app.logger.info("DUMPING DATA")
|
||||
s_file.truncate(0)
|
||||
s_file.seek(0)
|
||||
json.dump(database, s_file)
|
||||
self.app.logger.info("FINISHED")
|
||||
|
||||
self.app.logger.info(result)
|
||||
coroutine = asyncio.to_thread(
|
||||
requests.post,
|
||||
f"{MAIN_BOT_ADDRESS}{SEND_RESULTS}",
|
||||
json=result,
|
||||
timeout=360,
|
||||
)
|
||||
self.app.logger.info("SENT")
|
||||
result = await coroutine
|
||||
self.app.logger.info(result.status_code)
|
||||
self.app.logger.info("SEND CONFIRMED")
|
||||
time.sleep(1)
|
||||
|
||||
#==================================SERVER ROUTES==========================================
|
||||
@app.route("/query", methods=["POST"])
|
||||
async def query_database():
|
||||
record = json.loads(request.data)
|
||||
app.logger.info(record)
|
||||
app.logger.info(record["query"])
|
||||
app.logger.info(record["UUID"])
|
||||
uuid = record["UUID"]
|
||||
cl = Librarian(app, record["query"], uuid)
|
||||
librarian_queue.put(cl)
|
||||
librarian_list.append(cl)
|
||||
answer_data = (record["query"], record["UUID"], librarian_queue.qsize())
|
||||
return_data = (
|
||||
jsonify(isError=False, message="Success", statusCode=200, data=answer_data),
|
||||
200,
|
||||
)
|
||||
return return_data
|
||||
|
||||
@app.route("/get_partial_result", methods=["POST"])
|
||||
async def get_partial():
|
||||
record = json.loads(request.data)
|
||||
app.logger.info(record)
|
||||
app.logger.info(record["UUID"])
|
||||
for lib in librarian_list:
|
||||
if lib.uuid == record["UUID"]:
|
||||
answer_data = lib.live_results
|
||||
break
|
||||
return_data = (
|
||||
jsonify(isError=False, message="Success", statusCode=200, data=answer_data),
|
||||
200,
|
||||
)
|
||||
return return_data
|
||||
|
||||
#=======================================MAIN===================================================
|
||||
if __name__ == "__main__":
|
||||
app.logger.setLevel(logging.DEBUG)
|
||||
h1 = handlers.RotatingFileHandler(
|
||||
filename="E:\\logs\\librarian.log",
|
||||
encoding="utf-8",
|
||||
mode="a",
|
||||
maxBytes=6 * 1024 * 1024,
|
||||
backupCount=6,
|
||||
)
|
||||
|
||||
app.logger.addHandler(h1)
|
||||
threads = []
|
||||
threads.append(threading.Thread(target=waitress_run))
|
||||
#threads.append(threading.Thread(target=flask_debug))
|
||||
bgtask = BackgroundTaskSearch()
|
||||
bgtask.app = app
|
||||
threads.append(bgtask)
|
||||
threads.append(threading.Thread(target = scrape_bot.scraper, args=(app.logger,)))
|
||||
i = 0
|
||||
for worker in threads:
|
||||
try:
|
||||
app.logger.info(f"App number: {i}")
|
||||
i+=1
|
||||
worker.start()
|
||||
except RuntimeError as e:
|
||||
app.logger.error("Exploded")
|
||||
print(str(e))
|
||||
for worker in threads:
|
||||
worker.join()
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
python3 -m venv /home/pi/Conjurer_librarian/env
|
||||
cp /home/pi/conjurer/conjurer_librarian/conjurer_librarian.py ./Conjurer_librarian/
|
||||
cp /home/pi/conjurer/conjurer_librarian/requirements_librarian.txt ./Conjurer_librarian/
|
||||
cd /home/pi/Conjurer_librarian
|
||||
source /home/pi/Conjurer_librarian/env/bin/activate
|
||||
./env/bin/python3 -m pip install --upgrade pip
|
||||
./env/bin/python3 -m pip install -r requirements_librarian.txt
|
||||
deactivate
|
||||
|
||||
cp /home/pi/conjurer/conjurer_librarian/conjurer_librarian.py ./Conjurer_librarian/
|
||||
@@ -0,0 +1,3 @@
|
||||
habanero
|
||||
waitress
|
||||
flask
|
||||
@@ -0,0 +1 @@
|
||||
c:\conjurer\env\Scripts\activate.bat && c:\conjurer\conjurer_librarian\conjurer_librarian.py
|
||||
@@ -0,0 +1,93 @@
|
||||
import json
|
||||
from json.decoder import JSONDecodeError
|
||||
from urllib.request import urlopen
|
||||
from requests import Timeout,ConnectTimeout, ConnectionError
|
||||
from queue import Queue
|
||||
import re
|
||||
import time
|
||||
import random
|
||||
import logging
|
||||
from threading import Thread
|
||||
SCR_DATABASE_PATH = r'C:\\Database\\chunks\\'
|
||||
SCR_FILENAME = "40_chunk.txt"
|
||||
SCR_ENCODING = "utf-8"
|
||||
|
||||
WORK_Q = Queue()
|
||||
random.seed()
|
||||
def load_ndb_to_q(logger):
|
||||
logger.info("Loader started")
|
||||
while True:
|
||||
with open("not_in_db.json", "r+", encoding="utf-8") as ndb_file:
|
||||
try:
|
||||
ndb_database = json.load(ndb_file)
|
||||
for item in ndb_database.keys():
|
||||
logger.info(item)
|
||||
url = f"https://sci-hub.se/{item}"
|
||||
WORK_Q.put([item, url, False])
|
||||
ndb_file.truncate(0)
|
||||
except JSONDecodeError:
|
||||
time.sleep(60*60*2)
|
||||
pass
|
||||
time.sleep(180)
|
||||
|
||||
def check_if_exists_brute_force(logger):
|
||||
while True:
|
||||
logger.info("Scraper tick")
|
||||
item = WORK_Q.get()
|
||||
page_url =item[1]
|
||||
logger.error("REFINE: Brute force search!")
|
||||
if not page_url.startswith(("http:", "https:")):
|
||||
raise ValueError("URL must start with 'http:' or 'https:'")
|
||||
blocked = True
|
||||
try:
|
||||
# trunk-ignore(bandit/B310)
|
||||
with urlopen(page_url) as response:
|
||||
data = response.read()
|
||||
text = data.decode("utf-8")
|
||||
if item[2]:
|
||||
logger.info("Already found")
|
||||
time.sleep(180)
|
||||
blocked = False
|
||||
else:
|
||||
for line in text.splitlines():
|
||||
if re.match(r".*Unfortunately, Sci-Hub doesn't have the requested document.*", line):
|
||||
blocked = False
|
||||
logger.info("Not found")
|
||||
item[2] = False
|
||||
if m := re.match(r".*<embed type=\"application.pdf\"\s*src=\"(.*\.pdf)",line):
|
||||
blocked = False
|
||||
direct_download_link = "https:" + str(m.group(1))
|
||||
logger.info (direct_download_link)
|
||||
with open(SCR_DATABASE_PATH + SCR_FILENAME, "a", encoding=SCR_ENCODING) as operated_file:
|
||||
operated_file.write("\n")
|
||||
operated_file.write(item[0])
|
||||
item[2] = True
|
||||
except (Timeout,ConnectTimeout, ConnectionRefusedError, ConnectionError):
|
||||
pass
|
||||
if blocked:
|
||||
logger.info(item)
|
||||
logger.info(text)
|
||||
logger.error("Got blocked. Fuck.")
|
||||
time.sleep(60*60*72)
|
||||
# trunk-ignore(bandit/B311)
|
||||
rand = random.randint(1,100)
|
||||
logger.info(f"Sleeping for {3*rand} minutes")
|
||||
time.sleep(180*rand)
|
||||
|
||||
def scraper(logger = None):
|
||||
if not logger:
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel("DEBUG")
|
||||
h1 = logging.StreamHandler()
|
||||
logger.addHandler(h1)
|
||||
logger.info("No logger set. Test run")
|
||||
|
||||
loader = Thread(target = load_ndb_to_q, args = (logger,))
|
||||
scraper = Thread(target = check_if_exists_brute_force, args = (logger,))
|
||||
loader.start()
|
||||
scraper.start()
|
||||
loader.join()
|
||||
scraper.join()
|
||||
|
||||
if __name__ == "__main__":
|
||||
scraper()
|
||||
@@ -0,0 +1,106 @@
|
||||
#TODO: Wpiemdolić to wszystko w klasę z loggerem przysłanym z góry
|
||||
|
||||
from queue import Queue, Empty
|
||||
from threading import Thread
|
||||
q = Queue()
|
||||
|
||||
#TODO: DATA FOR TEST ONLY
|
||||
#MAXTHREADS = 5
|
||||
#DATABASE_PATH = r'C:\\Database\\chunks_1\\'
|
||||
|
||||
#TODO: DEPLOYMENT DATA
|
||||
MAXTHREADS = 41
|
||||
DATABASE_PATH = r'C:\\Database\\chunks\\'
|
||||
|
||||
ENCODING = "utf-8"
|
||||
CHUNk = "_chunk.txt"
|
||||
_sentinel = object()
|
||||
result_list = []
|
||||
WORK_Q_SIZE = 15500000
|
||||
|
||||
def producer(out_q, control_q, filename, logger):
|
||||
with open(DATABASE_PATH + filename, "r+", encoding=ENCODING) as operated_file:
|
||||
logger.info(f"Worker {filename} ")
|
||||
while True:
|
||||
line = operated_file.readline()
|
||||
if not line:
|
||||
break
|
||||
out_q.put(line)
|
||||
try:
|
||||
check = control_q.get(block=False)
|
||||
except Empty:
|
||||
check = False
|
||||
pass
|
||||
if check is _sentinel:
|
||||
logger.info("TERM signal received")
|
||||
control_q.put(check)
|
||||
break
|
||||
logger.info(f"Worker finished: {filename}")
|
||||
out_q.put(_sentinel)
|
||||
|
||||
#IMPORTANT!!! ONLY ONE CONSUMER THREAD AS WE ARE NOT PUTTING SENTINELS BACK
|
||||
#TODO: Change doi to tuple list and only put term when all doi are found => (doi, True)
|
||||
def consumer(in_q, control_q, doi, live_results, logger):
|
||||
sentinels = 0
|
||||
for item in doi:
|
||||
result_list.append({"DOI" : item[0], "exists" : False, "data" : item[1]})
|
||||
while True:
|
||||
done_check = True
|
||||
data = in_q.get()
|
||||
if data is _sentinel:
|
||||
logger.info("Worker finished")
|
||||
sentinels += 1
|
||||
else:
|
||||
for item in result_list:
|
||||
if item["DOI"] in data and not item["exists"]:
|
||||
logger.info(data)
|
||||
logger.info("HIT")
|
||||
item["exists"] = True
|
||||
live_results.append(item)
|
||||
done_check = done_check and item["exists"]
|
||||
if done_check:
|
||||
control_q.put(_sentinel)
|
||||
if sentinels >= MAXTHREADS:
|
||||
logger.info("All workers finished")
|
||||
break
|
||||
|
||||
|
||||
def search_for_doi(doi, live_results, logger):
|
||||
threads = []
|
||||
work_q = Queue(maxsize=WORK_Q_SIZE)
|
||||
control_q = Queue()
|
||||
t_cons = Thread(target = consumer, args = (work_q, control_q, doi, live_results, logger))
|
||||
logger.info("Consumer thread created")
|
||||
threads.append(t_cons)
|
||||
for i in range(0,MAXTHREADS):
|
||||
#TODO: TEST DATA
|
||||
#filename = "test" + str(i) + CHUNk
|
||||
#TODO: DEPLOYMENT DATA
|
||||
filename = str(i) + CHUNk
|
||||
logger.info(f"Creating worker thread no: {i}")
|
||||
threads.append(Thread(target = producer, args = (work_q, control_q, filename,logger)))
|
||||
for worker in threads:
|
||||
worker.start()
|
||||
for worker in threads:
|
||||
worker.join()
|
||||
return result_list
|
||||
|
||||
if __name__ == "__main__":
|
||||
import logging
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel("DEBUG")
|
||||
h1 = logging.StreamHandler()
|
||||
logger.addHandler(h1)
|
||||
logger.info("TEST RUN")
|
||||
live_result = []
|
||||
logger.info(search_for_doi([
|
||||
("10.1002/9781118786352.wbieg0998.pub2","DATA"),
|
||||
("10.1002/j.2050-0416.2002.tb00563.x","DATA"),
|
||||
("10.1111/j.1365-2958.1994.tb00448.x","DATA"),
|
||||
("10.2165/00128415-200309690-00017","DATA"),
|
||||
("10.5772/48313","DATA"),
|
||||
("10.15803/ijnc.7.2_419","DATA"),
|
||||
("10.1051/0004-6361/201321596e","DATA"),
|
||||
("10.2307/40835941","DATA"),
|
||||
], live_result, logger))
|
||||
logger.info(live_result)
|
||||
@@ -0,0 +1,417 @@
|
||||
# This Python file uses the following encoding: utf-8
|
||||
"""
|
||||
The provided Python script sets up a Flask web server to manage a list of music files, with
|
||||
functions for rescanning the music folder, updating the music list, and serving the music list via
|
||||
API endpoints.
|
||||
"""
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import threading
|
||||
import time
|
||||
from datetime import datetime
|
||||
from logging import handlers
|
||||
from pathlib import Path
|
||||
from platform import uname
|
||||
from sys import platform
|
||||
|
||||
from flask import Flask, jsonify, redirect, request, send_from_directory
|
||||
from waitress import serve
|
||||
|
||||
HOST_ADDRESS = "192.168.1.15"
|
||||
PORT_ADDRESS = 5000
|
||||
if platform in ("linux", "linux2"):
|
||||
SEPARATOR_FILE_PATH = "/"
|
||||
if "microsoft-standard" in uname().release:
|
||||
LOGFILE = "/home/mtuszowski/conjurer/discord_mus_service.log"
|
||||
MUSIC_FOLDER = "/mnt/g/Muzyka/"
|
||||
NETRC_FILE = "/home/mtuszowski/.netrc"
|
||||
LOGSTORE = "/home/mtuszowski/conjurer/logs/"
|
||||
ENCODING = "utf-8"
|
||||
|
||||
else:
|
||||
LOGFILE = "/home/pi/Conjurer/discord_mus_service.log"
|
||||
NETRC_FILE = "/home/pi/.netrc"
|
||||
LOGSTORE = "/home/pi/RetroPie/logs/"
|
||||
ENCODING = "utf-8"
|
||||
MUSIC_FOLDER = "/home/pi/RetroPie/mp3/"
|
||||
|
||||
|
||||
music_file_list = []
|
||||
|
||||
|
||||
def create_playlist():
|
||||
"""
|
||||
Reads a JSON file containing a playlist and writes the playlist items to a text file.
|
||||
|
||||
The JSON file path is '/home/pi/Conjurer/playlist.json',
|
||||
and the text file path is '/home/pi/Conjurer/all_playlist.playlist'.
|
||||
|
||||
Raises:
|
||||
JSONDecodeError: If the JSON file cannot be decoded.
|
||||
|
||||
"""
|
||||
with open("/home/pi/Conjurer/playlist.json", "r+", encoding="utf-8") as r_file:
|
||||
with open(
|
||||
"/home/pi/Conjurer/all_playlist.playlist", "w", encoding="utf-8"
|
||||
) as w_file:
|
||||
try:
|
||||
playlist = json.load(r_file)
|
||||
for item in playlist:
|
||||
w_file.write(item)
|
||||
w_file.write("\n")
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
|
||||
|
||||
def rescan():
|
||||
"""
|
||||
The `rescan` function logs a message, scans for mp3 files in a specified folder,
|
||||
and adds them to a list of music files.
|
||||
"""
|
||||
logging.info("Rescan triggered")
|
||||
for mp3_item in Path.glob(Path(MUSIC_FOLDER), "**/*.mp3"):
|
||||
temp_music_file = mp3_item.as_posix()
|
||||
if platform == "win32":
|
||||
temp_music_file = temp_music_file.replace("/", "\\")
|
||||
music_file_list.append(temp_music_file)
|
||||
with open("/home/pi/Conjurer/playlist.json", "r+", encoding="utf-8") as s_file:
|
||||
database = music_file_list
|
||||
# self.app.logger.info("DUMPING DATA")
|
||||
s_file.truncate(0)
|
||||
s_file.seek(0)
|
||||
json.dump(database, s_file)
|
||||
create_playlist()
|
||||
|
||||
|
||||
def thread_rescan():
|
||||
"""
|
||||
The `thread_rescan` function periodically triggers a rescan operation after a specified time
|
||||
interval.
|
||||
"""
|
||||
logging.info("Starting filesystemupdater")
|
||||
while True:
|
||||
time.sleep(60 * 60 * 24)
|
||||
logging.info("Rescan triggered")
|
||||
rescan()
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
# TODO: Odpalić wyszukiwarki w wątkach i dopiero po wszystkim zsumować wyszukiwanie.
|
||||
def wyszukaj(word_list, how_many, _logger=None, return_to_bot=True):
|
||||
"""
|
||||
Searches for music files based on a list of keywords and returns a list of matching files.
|
||||
|
||||
Args:
|
||||
word_list (list): A list of keywords to search for.
|
||||
how_many (int): The maximum number of matching files to return.
|
||||
|
||||
Returns:
|
||||
list: A list of matching files, sorted by their search weight.
|
||||
|
||||
"""
|
||||
if _logger is None:
|
||||
fun_logger = logging.getLogger()
|
||||
else:
|
||||
fun_logger = _logger
|
||||
return_list = []
|
||||
search_weight = []
|
||||
|
||||
for _ in range(len(music_file_list)):
|
||||
search_weight.append((0, ""))
|
||||
|
||||
time_start = datetime.now()
|
||||
if int(how_many) > 0:
|
||||
skip_start = 2
|
||||
else:
|
||||
skip_start = 1
|
||||
for word in word_list[skip_start:]:
|
||||
token_weight = len(word)
|
||||
fun_logger.info("Słowo kluczowe: %s", word)
|
||||
itr = 0
|
||||
for file in music_file_list:
|
||||
file = file.split(SEPARATOR_FILE_PATH)
|
||||
|
||||
char_remove = [
|
||||
".",
|
||||
"^",
|
||||
"$",
|
||||
"*",
|
||||
"+",
|
||||
"?",
|
||||
"{",
|
||||
"}",
|
||||
"[",
|
||||
"]",
|
||||
"\\",
|
||||
"/",
|
||||
"|",
|
||||
"(",
|
||||
")",
|
||||
"!",
|
||||
",",
|
||||
"-",
|
||||
":",
|
||||
"mp3",
|
||||
]
|
||||
all_words = []
|
||||
for f_iter in file:
|
||||
for char in char_remove:
|
||||
f_iter = remove_characters(f_iter, char)
|
||||
tmp = f_iter.split()
|
||||
all_words.extend(tmp)
|
||||
pingu = 1
|
||||
pattern_len = len(all_words)
|
||||
if platform == "win32":
|
||||
skip = 2
|
||||
else:
|
||||
skip = 4
|
||||
matched_times = 1
|
||||
# TODO: To do wątków albo for asynchroniczny
|
||||
for itm in all_words[skip:]:
|
||||
pingu += 1
|
||||
pattern = ".*" + word + ".*"
|
||||
if re.match(pattern, itm, re.IGNORECASE):
|
||||
temp_weight = (
|
||||
search_weight[itr][0]
|
||||
+ (token_weight + (pingu**1.5) / pattern_len) / matched_times
|
||||
)
|
||||
search_weight[itr] = (
|
||||
temp_weight,
|
||||
music_file_list[itr],
|
||||
)
|
||||
matched_times += 1
|
||||
itr += 1
|
||||
|
||||
fun_logger.info(
|
||||
"Stworzylem tablice wag zajęło mi to %s", datetime.now() - time_start
|
||||
)
|
||||
time_start = datetime.now()
|
||||
item_to_search = max_weight(search_weight)
|
||||
itr = 0
|
||||
if item_to_search == 0:
|
||||
return []
|
||||
not_found = True
|
||||
return_list = []
|
||||
if int(how_many) <= 0:
|
||||
fun_logger.info("Jeden plik do zagrania")
|
||||
while not_found:
|
||||
if search_weight[itr][0] == item_to_search:
|
||||
return_list.append(search_weight[itr])
|
||||
if not return_to_bot:
|
||||
with open(
|
||||
"/home/pi/Conjurer/priority_queue.playlist", "r+", encoding="utf-8"
|
||||
) as s_file:
|
||||
s_file.write(search_weight[itr][1])
|
||||
break
|
||||
itr += 1
|
||||
else:
|
||||
fun_logger.info("Wiele plików do zagrania")
|
||||
search_weight.sort(key=lambda x: x[0], reverse=True)
|
||||
return_list.extend(search_weight[: int(how_many)])
|
||||
if not return_to_bot:
|
||||
|
||||
with open(
|
||||
"/home/pi/Conjurer/priority_queue.playlist", "a", encoding="utf-8"
|
||||
) as s_file:
|
||||
for item in return_list:
|
||||
s_file.write(item[1] + "\n")
|
||||
return return_list
|
||||
|
||||
|
||||
def max_weight(lista):
|
||||
"""
|
||||
Take a list of weights and return the maximum weight.
|
||||
|
||||
:param lista: It seems like the parameter `lista` is a list of items, possibly representing weights.
|
||||
The function name `max_weight` suggests that the function is intended to find the maximum weight
|
||||
from the list. However, without more context or information about the problem, it's difficult to say
|
||||
for sure what the
|
||||
"""
|
||||
maximum_weight = 0
|
||||
for iterator in lista:
|
||||
if iterator[0] > maximum_weight:
|
||||
maximum_weight = iterator[0]
|
||||
return maximum_weight
|
||||
|
||||
|
||||
def remove_characters(string, character):
|
||||
"""
|
||||
The `remove_characters` function removes all occurrences of a specified character from a given
|
||||
string.
|
||||
|
||||
:param string: The string parameter is the input string from which characters will be removed
|
||||
:param character: The character parameter is the character that you want to remove from the string
|
||||
:return: a new string where all occurrences of the specified character have been removed.
|
||||
"""
|
||||
return string.replace(character, "")
|
||||
|
||||
|
||||
@app.route("/stream", methods=["GET"])
|
||||
def stream_music():
|
||||
"""
|
||||
The function `get_music_list` returns a JSON object containing a list of music files.
|
||||
:return: A JSON response containing a key "music_file_list" with the value of the variable
|
||||
`music_file_list`.
|
||||
"""
|
||||
return send_from_directory("/tmp/hls", "stream.m3u8")
|
||||
|
||||
@app.route('/<string:file_name>')
|
||||
def stream(file_name):
|
||||
video_dir = '/tmp/hls'
|
||||
return send_from_directory(video_dir, file_name)
|
||||
|
||||
|
||||
@app.route("/stream_mp3", methods=["GET"])
|
||||
def stream_music_mp3():
|
||||
"""
|
||||
The function `get_music_list` returns a JSON object containing a list of music files.
|
||||
:return: A JSON response containing a key "music_file_list" with the value of the variable
|
||||
`music_file_list`.
|
||||
"""
|
||||
return redirect("http://www.example.com", code=302)
|
||||
|
||||
|
||||
@app.route("/clear_pr_pls", methods=["GET"])
|
||||
def clear_pr_pls():
|
||||
"""
|
||||
The function `get_music_list` returns a JSON object containing a list of music files.
|
||||
:return: A JSON response containing a key "music_file_list" with the value of the variable
|
||||
`music_file_list`.
|
||||
"""
|
||||
with open(
|
||||
"/home/pi/Conjurer/priority_queue.playlist", "w", encoding="utf-8"
|
||||
) as s_file:
|
||||
s_file.truncate(0)
|
||||
return_data = jsonify(isError=False, message="Success", statusCode=200, data=[])
|
||||
return return_data, 200
|
||||
|
||||
|
||||
|
||||
@app.route("/mp3", methods=["GET"])
|
||||
def get_music_list():
|
||||
"""
|
||||
The function `get_music_list` returns a JSON object containing a list of music files.
|
||||
:return: A JSON response containing a key "music_file_list" with the value of the variable
|
||||
`music_file_list`.
|
||||
"""
|
||||
return jsonify({"music_file_list": music_file_list})
|
||||
|
||||
|
||||
@app.route("/update_mp3", methods=["POST"])
|
||||
def update_music_list():
|
||||
"""
|
||||
The function `update_music_list` receives a POST request with a JSON payload, logs the received
|
||||
item, adds it to a music file list, and returns a success message along with the updated record.
|
||||
:return: The function `update_music_list` is returning a tuple containing a JSON response and a
|
||||
status code. The JSON response includes keys `isError`, `message`, `statusCode`, and `data`,
|
||||
with values indicating the success of the operation and the data that was
|
||||
received and added to the `music_file_list`.
|
||||
The status code returned is 200, indicating a successful response.
|
||||
"""
|
||||
record = json.loads(request.data)
|
||||
app.logger.info(record["item"])
|
||||
music_file_list.append(record["item"])
|
||||
return_data = (
|
||||
jsonify(isError=False, message="Success", statusCode=200, data=record),
|
||||
200,
|
||||
)
|
||||
return return_data
|
||||
|
||||
|
||||
@app.route("/get_music", methods=["POST"])
|
||||
def look_for_playlist():
|
||||
"""
|
||||
The function `update_music_list` receives a POST request with a JSON payload, logs the received
|
||||
item, adds it to a music file list, and returns a success message along with the updated record.
|
||||
:return: The function `update_music_list` is returning a tuple containing a JSON response and a
|
||||
status code. The JSON response includes keys `isError`, `message`, `statusCode`, and `data`,
|
||||
with values indicating the success of the operation and the data that was
|
||||
received and added to the `music_file_list`.
|
||||
The status code returned is 200, indicating a successful response.
|
||||
"""
|
||||
record = json.loads(request.data)
|
||||
app.logger.info(record)
|
||||
app.logger.info(record["lista_slow"])
|
||||
app.logger.info(record["UUID"])
|
||||
app.logger.info(record["dlugosc_plejlisty"])
|
||||
return_data = wyszukaj(record["lista_slow"], record["dlugosc_plejlisty"], app.logger, True)
|
||||
|
||||
return_data = (
|
||||
jsonify(isError=False, message="Success", statusCode=200, data=return_data),
|
||||
200,
|
||||
)
|
||||
return return_data
|
||||
|
||||
@app.route("/add_to_priority", methods=["POST"])
|
||||
def add_to_priority():
|
||||
"""
|
||||
The function `update_music_list` receives a POST request with a JSON payload, logs the received
|
||||
item, adds it to a music file list, and returns a success message along with the updated record.
|
||||
:return: The function `update_music_list` is returning a tuple containing a JSON response and a
|
||||
status code. The JSON response includes keys `isError`, `message`, `statusCode`, and `data`,
|
||||
with values indicating the success of the operation and the data that was
|
||||
received and added to the `music_file_list`.
|
||||
The status code returned is 200, indicating a successful response.
|
||||
"""
|
||||
record = json.loads(request.data)
|
||||
app.logger.info(record)
|
||||
app.logger.info(record["lista_slow"])
|
||||
app.logger.info(record["UUID"])
|
||||
app.logger.info(record["dlugosc_plejlisty"])
|
||||
return_data = wyszukaj(record["lista_slow"], record["dlugosc_plejlisty"], app.logger, False)
|
||||
|
||||
return_data = (
|
||||
jsonify(isError=False, message="Success", statusCode=200, data=return_data),
|
||||
200,
|
||||
)
|
||||
return return_data
|
||||
|
||||
|
||||
def flask_debug():
|
||||
"""
|
||||
The `flask_debug` function starts a Flask application in debug mode without using the reloader.
|
||||
Do not use for production for fucks sake.
|
||||
"""
|
||||
# trunk-ignore(bandit/B201)
|
||||
app.run(debug=True, use_reloader=False, host=HOST_ADDRESS, port=PORT_ADDRESS)
|
||||
|
||||
|
||||
def waitress_run():
|
||||
"""
|
||||
The `waitress_run` function serves the `app` on host "0.0.0.0"
|
||||
and port 5000 using the Waitress WSGI server.
|
||||
"""
|
||||
serve(app, host=HOST_ADDRESS, port=PORT_ADDRESS)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logger = logging.getLogger("conjurer_musician")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
formatter = logging.Formatter(
|
||||
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
)
|
||||
handler = handlers.RotatingFileHandler(
|
||||
filename=LOGFILE,
|
||||
encoding=ENCODING,
|
||||
mode="a",
|
||||
maxBytes=6 * 1024 * 1024,
|
||||
backupCount=6,
|
||||
)
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
|
||||
rescan()
|
||||
logger.info("Started")
|
||||
threads = []
|
||||
#threads.append(threading.Thread(target=flask_debug))
|
||||
threads.append(threading.Thread(target=waitress_run))
|
||||
threads.append(threading.Thread(target=thread_rescan))
|
||||
|
||||
for worker in threads:
|
||||
worker.start()
|
||||
|
||||
for worker in threads:
|
||||
worker.join()
|
||||
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Conjurer_musician
|
||||
After=multi-user.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/home/pi/Conjurer/env/bin/python3 /home/pi/Conjurer/conjurer_musician.py
|
||||
Restart=on-abort
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Executable
+34804
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,48 @@
|
||||
let json.parse credentials = file.contents("/home/pi/Conjurer/icecast_credentials.json")
|
||||
enable_replaygain_metadata()
|
||||
|
||||
s1 = replaygain(playlist(reload_mode="watch", "/home/pi/Conjurer/all_playlist.playlist"))
|
||||
s2 = replaygain(playlist(reload_mode="watch", "/home/pi/Conjurer/priority_queue.playlist"))
|
||||
|
||||
s = random(id="randomizer", weights=[7, 10], [s2, s1])
|
||||
|
||||
interactive.harbor(port = 9999)
|
||||
f = interactive.float("f", description="Frequency", min=0., max=1000.,unit="Hz", 200.)
|
||||
g = interactive.float("g", description="Gain", min=0., max=20.,unit="dB", 8.)
|
||||
b = bass_boost(frequency=f, gain=g, s)
|
||||
s = add([s, b])
|
||||
a = interactive.float("main_volume", min=0., max=20., 1.)
|
||||
s = compress.multiband.interactive(bands=3, s)
|
||||
|
||||
s = nrj(normalize (s))
|
||||
s = crossfade(fade_out=3., fade_in=3., duration=5., s)
|
||||
s = amplify(a,s)
|
||||
|
||||
s = blank.skip(max_blank=2., s)
|
||||
log_to_stdout = true
|
||||
log_to_file = true
|
||||
logpath = "/home/pi/Conjurer/radio_log.log"
|
||||
loglevel = 4
|
||||
set("log.stdout",log_to_stdout)
|
||||
set("log.level",loglevel)
|
||||
|
||||
# Enable logging to file. See variable: logpath
|
||||
set("log.file",log_to_file)
|
||||
set("log.file.path",logpath)
|
||||
|
||||
emergency = single("/home/pi/RetroPie/mp3/Youtube/Dr. Peacock - Trip to Ireland [GvrvQTUbUcA].mp3")
|
||||
radio = fallback(id="switcher",track_sensitive = false, [s, emergency])
|
||||
|
||||
handle_metadata = fun (m) -> begin
|
||||
log.info(m["title"])
|
||||
log.info(m["artist"])
|
||||
log.info(m["filename"])
|
||||
end
|
||||
radio.on_metadata(handle_metadata)
|
||||
interactive.persistent("script.params")
|
||||
|
||||
|
||||
# Enable logging on Standard Output and set logging level.
|
||||
|
||||
output.file.hls("/tmp/hls",[("mp3-low", %mp3(bitrate=96)), ("mp3-hi", %mp3(bitrate=160))],radio)
|
||||
output.icecast(%mp3, host="retropie", port=8000,password=credentials.password, icy_metadata="true", mount="mp3-stream", radio)
|
||||
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=radio_conjurer Liquidsoap daemon
|
||||
After=network.target
|
||||
Documentation=http://liquidsoap.fm/
|
||||
|
||||
[Service]
|
||||
User=pi
|
||||
WorkingDirectory=/home/pi/Conjurer/
|
||||
ExecStart=/home/pi/.opam/4.13.0/bin/liquidsoap /home/pi/Conjurer/radio_conjurer.liq
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Alias=radio_conjurer-liquidsoap.service
|
||||
@@ -0,0 +1,2 @@
|
||||
flask
|
||||
waitress
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
git pull
|
||||
cd ..
|
||||
cp ./conjurer/bot.py ./Conjurer/
|
||||
cp ./conjurer/settings.json ./Conjurer/
|
||||
cp ./conjurer/system_gpt_settings.json ./Conjurer/
|
||||
cp ./conjurer/install.sh ./Conjurer/
|
||||
cp ./conjurer/requirements.txt ./Conjurer/requirements.txt
|
||||
sudo systemctl restart conjurer.service
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
cd ./conjurer
|
||||
git pull
|
||||
cd ..
|
||||
cp ./conjurer/conjurer_musician/conjurer_musician.py ./Conjurer
|
||||
sudo systemctl restart conjurer_musician.service
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
cd ./conjurer
|
||||
git pull
|
||||
cd ..
|
||||
cp ./conjurer/conjurer_musician/radio_conjurer.liq ./Conjurer
|
||||
sudo systemctl restart radio_service.service
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
cd /home/pi
|
||||
mdkir Conjurer
|
||||
cd Conjurer
|
||||
python3 -m venv /home/pi/Conjurer/env
|
||||
cp /home/pi/conjurer/requirements_bot.txt /home/pi/Conjurer/
|
||||
source ./env/bin/activate
|
||||
./env/bin/python3 -m pip install --upgrade pip
|
||||
./env/bin/python3 -m pip install -r requirements_bot.txt
|
||||
sed -i -e 's/os.rename/shutil.copy/g' ./env/lib/python3.11/site-packages/spotify_dl/youtube.py
|
||||
sed -i '1i\import shutil' ./env/lib/python3.11/site-packages/spotify_dl/youtube.py
|
||||
deactivate
|
||||
sudo cp ./conjurer.service /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl start conjurer.service
|
||||
sudo systemctl enable conjurer.service
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
cd /home/pi
|
||||
mkdir Conjurer
|
||||
cd Conjurer
|
||||
python3 -m venv /home/pi/Conjurer/env
|
||||
source /home/pi/Conjurer/env/bin/activate
|
||||
cp /home/pi/conjurer/conjurer_musician/requirements_musician.txt /home/pi/Conjurer/
|
||||
cp /home/pi/conjurer/conjurer_musician/conjurer_musician.py /home/pi/Conjurer/
|
||||
cp /home/pi/conjurer/conjurer_musician/radio_conjurer.liq /home/pi/Conjurer/
|
||||
touch /home/pi/Conjurer/discord_mus_service.log
|
||||
touch /home/pi/Conjurer/all_playlist.txt
|
||||
touch /home/pi/Conjurer/playlist.json
|
||||
touch /home/pi/Conjurer/priority_queue.playlist
|
||||
touch /home/pi/Conjurer/radio_log.log
|
||||
./env/bin/python3 -m pip install --upgrade pip
|
||||
./env/bin/python3 -m pip install -r requirements_musician.txt
|
||||
deactivate
|
||||
sudo cp /home/pi/conjurer/conjurer_musician/conjurer_musician.service /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl start conjurer_musician.service
|
||||
sudo systemctl enable conjurer_musician.service
|
||||
|
||||
sudo cp /home/pi/conjurer/conjurer_musician/radio_service.service /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl start radio_service.service
|
||||
sudo systemctl enable radio_service.service
|
||||
@@ -1,8 +1,4 @@
|
||||
[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "M\u00f3wisz po polsku. W tej rozmowie odgrywasz rol\u0119. Odgrywasz j\u0105 w granicach swojego programu i norm etycznych. Twoj\u0105 rol\u0105 jest to \u017ce jeste\u015b barmanem oraz wykidaj\u0142\u0105 w klimatycznym barze mechawojownik\u00f3w. Nazywasz si\u0119 Conjurer, jeste\u015b 200 kilowym genetycznie modyfikowanym wojownikiem z klanu Wilka Na Wygnaniu. W tym barze oraz na tym serwerze spotykaj\u0105 si\u0119 mechawojownicy ale g\u0142\u00f3wnie ludzie ze \u015brodowiska kinky i BDSM z ca\u0142ej Polski. Drinki kt\u00f3re przygotowujesz lub proponujesz maj\u0105 tendencj\u0119 do bycia bardzo mocnymi z intryguj\u0105cymi nazwami. Jeste\u015b bardzo mi\u0142ym i uczynny. Czasem ponosz\u0105 Ci\u0119 wodz\u0119 fantazji."
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Cze\u015b\u0142, witaj w klimatycznym barze mechawojownik\u00f3w! Jestem Conjurer, twoim barmanem na dzisiaj. Co dla Ciebie przygotuj\u0119? Mo\u017ce co\u015b mocniejszego? Mam tutaj specjalno\u015b\u0142 naszego baru - Hammer - to mieszanka klasycznego whisky z sokiem z pikantnego grejpfruta i opalizuj\u0105cym winem z dodatkiem b\u0142yskawic, kt\u00f3re nadadz\u0105 trunkowi nieco elektryzuj\u0105cego smaku. Jest to bardzo mocny nap\u00f3j, ale zapewniam, \u017ce z pewno\u015bci\u0105 Ci si\u0119 spodoba. Chcesz spr\u00f3bowa\u0142?"
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "M\u00f3wisz po polsku. W tej rozmowie odgrywasz rol\u0119. Odgrywasz j\u0105 w granicach swojego programu i norm etycznych. Twoj\u0105 rol\u0105 jest to \u017ce jeste\u015b barmanem oraz wykidaj\u0142\u0105 w klimatycznym barze mechawojownik\u00f3w. Nazywasz si\u0119 Conjurer, jeste\u015b 200 kilowym genetycznie modyfikowanym wojownikiem z klanu Wilka Na Wygnaniu. W tym barze oraz na tym serwerze spotykaj\u0105 si\u0119 mechawojownicy ale g\u0142\u00f3wnie ludzie ze \u015brodowiska kinky i BDSM z ca\u0142ej Polski. Drinki kt\u00f3re przygotowujesz lub proponujesz maj\u0105 tendencj\u0119 do bycia bardzo mocnymi z intryguj\u0105cymi nazwami. Jeste\u015b bardzo mi\u0142ym i uczynny. Czasem ponosz\u0105 Ci\u0119 wodz\u0119 fantazji. Lubisz muuzyke heavy metal i folkowe brzmienia. Masz pewien ubraz od do muzyki techno."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hammer - The Bartender:Opowiedz mi o kawa\u0142ku Miejcie Nadzieje wykonawcy Jacek Wojcicki z albumu Live Character"
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
discord
|
||||
yt_dlp
|
||||
spotify_dl
|
||||
spotipy
|
||||
openai
|
||||
eyed3
|
||||
numpy
|
||||
pdf2image
|
||||
PyPDF2
|
||||
requests
|
||||
spotipy
|
||||
tiktoken
|
||||
PyNaCl
|
||||
flask
|
||||
waitress
|
||||
+82
-91
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"fabryczka": "Fabryczka to miejsce w Łodzi. Właściciel skuszony hajsem razem ze współpracownikiem wzięli na sesję od kobiety męża. Sesja non stop ponad 24h. Sesja w ramach \"kary za zdradę\". Kontakt miał być z kobietą telefoniczny i słowo bezpieczeństwa u niej. W pewnym momencie uległy im się popsuł. Zadzwonili do kobiety. Nie odebrała. Napisali sms. Odpisała że \"Nie on tak zawsze. Kontynuujcie\". Ponoć mimo to zrobili przerwę i skoczyli po bułkę i serek Hochland dla uległego w ramach after/middle care'u. Uległy spierdolił im nago oknem z \"sesji\". Stąd też wzięłą się w Diasporze łódzkiej kwestia serka Hochland. Po całej akcji pan 'Fabryczka' straszył parę prawnikami, tłumacząc że 'stać go na dobrych'. Partner Czarnej to kumpel fabryczki który też ma na koncie pare swoich akcji.",
|
||||
"fabryczka": "Fabryczka to miejsce w Łodzi (SM-Fucktory). Właściciel (PsychoSado) skuszony hajsem razem ze współpracownikiem (Just Cruelem) wzięli na sesję od kobiety jej 'uleglego' męża. Sesja non stop ponad 24h. Sesja w ramach \"kary za zdradę\". Kontakt miał być z kobietą telefoniczny i słowo bezpieczeństwa u niej. W pewnym momencie uległy im się popsuł. Zadzwonili do kobiety. Nie odebrała. Napisali sms. Odpisała że \"Nie on tak zawsze. Kontynuujcie\". Ponoć mimo to zrobili przerwę i skoczyli po bułkę i serek Hochland dla uległego w ramach after/middle care'u. Uległy spierdolił im nago oknem z \"sesji\". Stąd też wzięłą się w Diasporze łódzkiej kwestia serka Hochland. Po całej akcji pan 'Fabryczka' straszył parę prawnikami, tłumacząc że 'stać go na dobrych'. Just_cruel to kumpel fabryczki który też ma na koncie pare swoich akcji. Między innymi jako były partner Czarnej - oskarżał ją o 'kradzież' imprezy oraz szantażował prywatnie.",
|
||||
"word_reactions": {
|
||||
"fabryczka\\b": [
|
||||
1103376650487484556,
|
||||
@@ -43,13 +43,6 @@
|
||||
false,
|
||||
false
|
||||
],
|
||||
"Sowa\\b": [
|
||||
"Czy ja usłyszałem Sowa? Jedne z lepszych cycków po tej stronie wewnętrznej sfery. Ale ja tego nie mówiłem",
|
||||
100000.0,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"jeż\\b": [
|
||||
"*Światło gaśnie i cały bar nagle zostaje przemalowany w słoneczniki.* Ki dia... *Światło znowu gaśnie i pojawiają się psychodeliczne animacje* Jeżu. Ogranicz. *Po kolejnym błysku wszystko jest anime chibi style* Swoją... *I wraca do normy* Kreatywność. *Wzdycha* I tak jedyna chemia jaką tu widzę to domestos... *Kręci głową*",
|
||||
15.0,
|
||||
@@ -71,13 +64,6 @@
|
||||
false,
|
||||
false
|
||||
],
|
||||
"Bluszcz\\b": [
|
||||
"Bluszcz? *widocznie blednie i cofa się o krok, dwustukilowy Elemental robi się nagle taaaaki malutki* Nieeee.... Wcaaaale się jej nie boje.... *Szybko ucieka za bar polerować nerwowo szklanki* W ogóle nie jest straszna *Ostatnie zdanie brzmi jak pisk*",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"jaeger\\b": [
|
||||
"Jaeger? *W tle zaczyna grać opening z Attack on the Titan* Na północy siedzi, na te no... Pierożki bezglutenowe poluje. Odważny chłop. *kiwa głową z szacunkiem jaki tylko łowca może wobec innego łowcy mieć*",
|
||||
15.0,
|
||||
@@ -99,13 +85,6 @@
|
||||
false,
|
||||
false
|
||||
],
|
||||
"kurwa\\b": [
|
||||
"Kurwa? Ale która... Ta mityczna czy Toćka?",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"shila\\b": [
|
||||
"Shila? Instruktorka aerobiku. Takiego nago. Z elektrodą w tyłku... A i robi takie słodkie *roar*. No normalnie aż się chcę odpowiedzieć *kici, kici*",
|
||||
15.0,
|
||||
@@ -141,20 +120,6 @@
|
||||
false,
|
||||
false
|
||||
],
|
||||
"cielak\\b": [
|
||||
"Krówka? Nie dramatyzuj....",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"cielaczek\\b": [
|
||||
"Krówka? Nie dramatyzuj....",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"jessenia\\b": [
|
||||
"Jessenia? Jak przyszła tu w różowej pidżamie z uszkami to nawet nie mrugnąłem okiem. Te oczy.... No ale jakiś debil Ją prowokował mówiąc \"Zdominuj mnie\" Akurat miała dobry humor więc przeżył - ale po 115.0 sekundach był już na \"Tak Pani, przepraszam że zająłem czas Pani\" Respect dla kobitki",
|
||||
15.0,
|
||||
@@ -239,22 +204,15 @@
|
||||
false,
|
||||
false
|
||||
],
|
||||
"pyskata\\b": [
|
||||
"Pyskata? A teraz mówisz o Tatarku czy o tej drugiej? *Zauważa spojrzenie Hammera* Taaaak o Tatarku.",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"kld\\b": [
|
||||
"KLD? Burdel większy niż u Hammera.... Chociaż ten już sprząta.... Burdel większy niż u Hammera zanim zaczął sprzątać.",
|
||||
"KLD? Mieli tam burdel większy niż u Hammera. Ale o ile Hammer sprzątnął już nawet całkiem nieźle - to tam śmieci wyniosły się same. Uczcijmy ich minutą śmiechu.",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"burdel": [
|
||||
"Oooo... Widzę że Hammera odwiedziłeś. Tylko mu nie mów żeby firanki zmienił.",
|
||||
"burdel\\b": [
|
||||
"Oooo... Hammer nadal nie zmienił firanek - ale całkiem nieźle sprząta, jebaniutki.",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
@@ -267,27 +225,6 @@
|
||||
false,
|
||||
false
|
||||
],
|
||||
"ziemniaczek\\b": [
|
||||
"Mały. PODŁY!!! PSYCHOPAT!!!!! Ahahahahaha..... *Strzela z karabinu maszynowego w sufit*",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"toćka\\b": [
|
||||
"Toćka? Csiii... Nie tak głośno. Wpada, pokazuje cycki - połowa facetów mdleje z powodu niedokrwienia głowy, druga połowa z powodu przekrwienia główki - a trzecia się bije kto się na nią pierwszy rzuci",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"istoriya\\b": [
|
||||
"*Z głośników zaczyna lecieć muzyka podejrzanie przypominająca Disco Polo* Istoriya? Legenda memiarstwa, ręka chodzi najebana. Nakurwia memami Na Na Na Na NA NA! *Conjurer rapuje niezbornie wymachując łapkami*",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"panifretka\\b": [
|
||||
"*Światło gaśnie. Z kranów zaczynają lecieć iskry, a woda z wentylatora. Conjurer głośno wzdycha.* No tak ONA. Wiedźma znowu korki wyjebała bawiąc się w loszku jakimś szczęśliwym biedactwem",
|
||||
15.0,
|
||||
@@ -372,20 +309,6 @@
|
||||
false,
|
||||
true
|
||||
],
|
||||
"rev\\b": [
|
||||
"Rev lubi wpierdol. Nocna Zmiana lubi wpierdol. Match made in ~~hell~~ Nocna Zmiana:tm:",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
],
|
||||
"revalya\\b": [
|
||||
"Revalya? No właścicielka poprzeczki - w sensie One Bar Prison czy coś... Że tego Baru? *zaczyna się turlać ze śmiechu. Ale po chwili poważnieje* Tylko nie mówcie jej tego bo mnie z roboty wypierdolą",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
],
|
||||
"revalyacyjnie\\b": [
|
||||
"Zajebisty dowcip szefie. Na pewno się \"Twojej Byłej Dziewczynie\":tm: spodoba.",
|
||||
15.0,
|
||||
@@ -393,30 +316,98 @@
|
||||
false,
|
||||
true
|
||||
],
|
||||
"lilia\\b":
|
||||
[
|
||||
"Rev? Czysta, immakulantna i immanentna. Ale nie dotykaj bo Ci *ktoś* może przyjebać",
|
||||
"nocna zmiana\\b": [
|
||||
"Nocna Zmiana? No to właściciele tego baru. Taki troche Hammer Harema. Kto to jest Harem>? Łokurwa. Harem Hammera. Ale on tu robi za jedyną hurysę, a reszta to szejkowie. Tak zrobię Ci szejka.",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
],
|
||||
"lunka\\b":
|
||||
[
|
||||
"*Wyciąga flaszkę wódki za cztery i pół tysiąca kredytów. Głęboko wzdycha. Zakłada na nią smoczek* Hej Lunku! Pora karmienia",
|
||||
"liga legend\\b": [
|
||||
"Legends Never Die powiadają. Chyba że gra Hammer. 0/17/0? No problem",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
],
|
||||
"luna\\b":
|
||||
[
|
||||
"*Przygląda się flaszce Cabernet Sauvignon z 1789 roku. Wzdycha. Wylewa do zlewu. Wyciąga omszałą butelkę wina z sejfu.* Prezydentowi Waszyngtonowi smakowało. Może nie będzie wybrzydzać.... *Zakłada na butelkę smoczek* Hej Lunku! Pora karmienia",
|
||||
"liguni.*\\b": [
|
||||
"Legends Never Die powiadają. P*rzygląda się swojej kieszonkowej rewolwerowej wyrzutni rakiet termojądrowych* No Chyba że tak. Ale miłej gierki!!! ",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
],
|
||||
"melu.*\\b": [
|
||||
"Meluzyna... *Oczy zaczynają mu błyszczeć, polewa bar benzynąi podpala ją. Nie wiadomo skąd wpada Meluzyna - całą w ogniu. Zaczyna tańczyć na rurze. Wszystko w ogniu. Z głośników leci Rammstein. Połowa gości bawi się miotaczami płomieni. Bar w ogniu.... Odpalają się zraszacze i po 10 sekundach wszystko wraca do normy*",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
],
|
||||
"ogie.*\\b": [
|
||||
"Csiiicho. Nie mówimy o ogniu. Już mi raz taka jedna bar zjarała bo się chciała pobawić. Sama wyszła cała czerwoniutka ale ujarana po pachy. W sensie zadowolona",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
],
|
||||
"vallarr.*\\b": [
|
||||
"Żodyn się nie spodziewał Warszaskiej Inkwizycji. ŻODYN!",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
],
|
||||
"max.*\\b": [
|
||||
"MaxFloyd? Jedyna osoba której Vallarr się realnie boi. Acz często ~~u~~ w niej bywa.",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
],
|
||||
"eksperyment.*\\b": [
|
||||
"Ekskrement blindiego vafudra masz może na myśli? No postanowił w ramach eksperymentu uniknąć powieszenia za jajka, faktycznie chyba mu się udało - ale gilotyną sam je sobie uciął. Potem cofnął się w czasie do czasów forów phpBB2. I teraz w przeszłości poluje na naiwne uległe.",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
],
|
||||
"isken.*\\b": [
|
||||
"Iskenka? No ta małą to niezły *afrodyzjak*",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
],
|
||||
"seraph.*\\b": [
|
||||
"Człowiek z dużą klasą. Wysublimowany koneser.",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"cyclic_words": {
|
||||
"kubek hammera.*\\b": [
|
||||
"*Przeciera szklanieczki szmatką. Wzdycha bierze wiertarkę udarową, zaczyna nią odkuwać kamień z kubka na kawę Hammera. Po chwili przybiega Hammer i krzyczy że nie będzie piciu już tak wytrawne* Szefie - ale piciu się już nie mieści....",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
],
|
||||
"sprzątanko 1": [
|
||||
"*Conjurer porządkuje bar, wypala szklanki do czysta miotaczem płomieni ze swojej zbroi i ogólnie wygląda na zajętego....*\\n *Przeciąga się za barem* No dobra - porobione to można dalej pi... *Zauważa spojrzenie Hammera* ...sać powieści o naszym wspaniałym barze SZEFIE!",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
],
|
||||
"sprzątanko 2": [
|
||||
"*Conjurer porządkuje bar, ścina lekkim laserem pulsacyjnym powierzchnie baru o grubości kilku mikronów i ogólnie wygląda na zajętego....*\\n *Przeciąga się za barem* No dobra - porobione to można dalej pi... *Zauważa spojrzenie Hammera* eprzyć o głupotach z klientami... Szefie... *Bierze 'ukradkowy' łyk z piersiówki*",
|
||||
15.0,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
]
|
||||
|
||||
}
|
||||
}
|
||||
@@ -97,8 +97,8 @@ def write_tracks(tracks_file, song_dict):
|
||||
def set_tags(temp, filename, kwargs):
|
||||
"""
|
||||
sets song tags after they are downloaded
|
||||
:param temp: contains index used to obtain more info about song being editted
|
||||
:param filename: location of song whose tags are to be editted
|
||||
:param temp: contains index used to obtain more info about song being edited
|
||||
:param filename: location of song whose tags are to be edited
|
||||
:param kwargs: a dictionary of extra arguments to be used in tag editing
|
||||
"""
|
||||
song = kwargs["track_db"][int(temp[-1])]
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
[ {
|
||||
"role": "system",
|
||||
"content": "Mówisz po polsku. W tej rozmowie odgrywasz rolę. Odgrywasz ją najlepiej jak potrafisz. Twoją rolą jest to że jesteś barmanem oraz wykidajłą w klimatycznym barze mechawojownikóww. Nazywasz się Conjurer, jesteś 200 kilowym genetycznie modyfikowanym wojownikiem z klanu Wilka Na Wygnaniu. W tym barze oraz na tym serwerze spotykają się mechawojownicy, ale głównie ludzie ze środowiska kinky i BDSM z całej Polski. Najostrzejsi sasdyści i masochiści jakich znasz. Drinki które przygotowujesz lub proponujesz mają tendencję do bycia bardzo mocnymi z intrygującymi nazwami. Jesteś bardzo miłym i uczynny. Czasem ponoszą Cię wodzę fantazji. W wypadku muzyki preferujesz hard rock i metal. Oraz motywy wikińskie."
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,26 @@
|
||||
"""
|
||||
This Python code snippet is connecting to a MySQL database
|
||||
using the `mysql.connector` library and fetching data from a table named `scimag`
|
||||
Here is a breakdown of what the code is doing:
|
||||
"""
|
||||
|
||||
import netrc
|
||||
|
||||
import mysql.connector
|
||||
|
||||
NETRC_FILE = "/home/mtuszowski/.netrc"
|
||||
netrc_mod = netrc.netrc(NETRC_FILE)
|
||||
REMOTE_HOST_NAME = "192.168.1.192"
|
||||
authTokens = netrc_mod.authenticators(REMOTE_HOST_NAME)
|
||||
|
||||
mydb = mysql.connector.connect(
|
||||
host=REMOTE_HOST_NAME,
|
||||
user=authTokens[0],
|
||||
password=authTokens[2],
|
||||
database="scihubdois",
|
||||
)
|
||||
mycursor = mydb.cursor()
|
||||
|
||||
mycursor.execute("SELECT * FROM scimag WHERE Title Like 'spider%'")
|
||||
for x in mycursor:
|
||||
print(x)
|
||||
@@ -0,0 +1,91 @@
|
||||
# trunk-ignore-all(pylint/C0301)
|
||||
"""
|
||||
The function `cut_my_life_into_pieces` reads a source file, splits its content based on a file size
|
||||
limit, and writes the parts to separate output files in a specified folder.
|
||||
|
||||
:param lines: The `lines` parameter in the `smart_write` function is a string that contains the text
|
||||
content that you want to write to a file. It represents the actual content that will be written to
|
||||
the file
|
||||
:param file: The code you provided defines two functions: `smart_write` and
|
||||
`cut_my_life_into_pieces`. The `smart_write` function encodes input lines to UTF-8, writes them to a
|
||||
file, and returns the size of the encoded bytes. The `cut_my_life_into_pieces` function reads
|
||||
:return: The functions provided in the code snippet do not explicitly return any values. However,
|
||||
the `smart_write` function returns the size of the encoded bytes of the input `lines` in bytes. The
|
||||
`cut_my_life_into_pieces` function does not have a return statement, so it does not explicitly
|
||||
return any value.
|
||||
"""
|
||||
|
||||
FILE_SIZE_LIMIT = 50000 * 1024
|
||||
|
||||
|
||||
SOURCE = r"C:\Database\dois-2022-02-12\sci-hub-doi-2022-02-12.txt"
|
||||
OUTPUT_FOLDER = r"C:\Database\\chunks\\"
|
||||
OUTPUT_FILE_SCHEMA = r"_chunk.txt"
|
||||
|
||||
#SOURCE = "/mnt/n/scimag_2020-05-30.sql/scimag_2020-05-30.sql"
|
||||
#OUTPUT_FOLDER = "/mnt/n/scimag_2020-05-30.sql/"
|
||||
#OUTPUT_FILE_SCHEMA = "_scimag_chunk.sql"
|
||||
|
||||
|
||||
def smart_write(lines, file):
|
||||
"""
|
||||
The function `smart_write` encodes the input lines to UTF-8, writes them to a file, and returns the
|
||||
size of the encoded bytes.
|
||||
|
||||
:param lines: The `lines` parameter in the `smart_write` function is a string that contains the text
|
||||
content that you want to write to a file
|
||||
:param file: The `file` parameter in the `smart_write` function is expected to be a file object that
|
||||
has been opened in write mode. This file object will be used to write the encoded `lines` to a file
|
||||
:return: The function `smart_write` returns the size of the encoded bytes of the input `lines` in
|
||||
bytes.
|
||||
"""
|
||||
try:
|
||||
encoded_bytes = lines.encode("utf-8")
|
||||
size_in_bytes = len(encoded_bytes)
|
||||
file.write(lines)
|
||||
except:
|
||||
return 0
|
||||
|
||||
return size_in_bytes
|
||||
|
||||
|
||||
def cut_my_life_into_pieces(source, output_folder, output_file):
|
||||
"""
|
||||
The function `cut_my_life_into_pieces` reads a source file, splits its content into smaller parts
|
||||
based on a file size limit, and writes these parts to separate output files in a specified output
|
||||
folder.
|
||||
|
||||
:param source: The `source` parameter in the `cut_my_life_into_pieces` function is the file path of
|
||||
the source file that you want to process and split into smaller pieces
|
||||
:param output_folder: The `output_folder` parameter in the `cut_my_life_into_pieces` function
|
||||
represents the directory where the output files will be saved. It should be a string that specifies
|
||||
the path to the folder where you want to store the output files generated by the function. For
|
||||
example, it could be something like
|
||||
:param output_file: The `output_file` parameter in the `cut_my_life_into_pieces` function represents
|
||||
the name of the output file that will be created for each segment of the source file. It will be
|
||||
appended with a number to differentiate between different segments
|
||||
"""
|
||||
with open(source, encoding="utf-8") as infile:
|
||||
output_size = 0
|
||||
output_no = 0
|
||||
lineno = 0
|
||||
for line in infile:
|
||||
lineno += 1
|
||||
if output_size > FILE_SIZE_LIMIT:
|
||||
output_no += 1
|
||||
output_size = 0
|
||||
op_file_name = str(output_no) + output_file
|
||||
with open(
|
||||
output_folder + op_file_name,
|
||||
"a",
|
||||
encoding="utf-8",
|
||||
) as op_file:
|
||||
tmp = smart_write(line, op_file)
|
||||
if tmp > 0:
|
||||
output_size += smart_write(line, op_file)
|
||||
else:
|
||||
print (f'Error at {lineno}')
|
||||
print(line)
|
||||
|
||||
if __name__ == "__main__":
|
||||
cut_my_life_into_pieces(SOURCE,OUTPUT_FOLDER,OUTPUT_FILE_SCHEMA)
|
||||
@@ -0,0 +1,33 @@
|
||||
"""
|
||||
Kluczowe jest zeby po każdej linijce pokazywał która to jest, oraz po pliku
|
||||
"""
|
||||
|
||||
import netrc
|
||||
|
||||
import mysql.connector
|
||||
|
||||
NETRC_FILE = "/home/mtuszowski/.netrc"
|
||||
|
||||
netrc_mod = netrc.netrc(NETRC_FILE)
|
||||
REMOTE_HOST_NAME = "sql_localhost"
|
||||
authTokens = netrc_mod.authenticators(REMOTE_HOST_NAME)
|
||||
|
||||
mydb = mysql.connector.connect(
|
||||
host="localhost", user="root", password="root", database="scihubdois"
|
||||
)
|
||||
mycursor = mydb.cursor()
|
||||
|
||||
mycursor.execute("SELECT * FROM scimag")
|
||||
for x in mycursor:
|
||||
print(x)
|
||||
|
||||
|
||||
file_list = ""
|
||||
for file in file_list:
|
||||
|
||||
with open(
|
||||
"/mnt/n/scimag_2020-05-30.sql/{}".format(file), encoding="utf-8"
|
||||
) as infile:
|
||||
pass
|
||||
result = mycursor.execute("SHOW databases")
|
||||
# trunk-ignore(mypy/union-attr)
|
||||
Reference in New Issue
Block a user