diff --git a/README.md b/README.md index f6b05bd..4fba606 100644 --- a/README.md +++ b/README.md @@ -49,60 +49,3 @@ # 一些信息 - 使用了Python3.6 的标准库`Sqlite3`进行数据库操作 -- 当前支持的主题如下 - -
-foot
-gelbooru
-gelbooruh
-moebooru
-moebooruh
-g
-cripple
-blacked
-allgirl
-rule34
-steambanner
-lefty
-erpg
-crewbooru
-hgoon
-sthg
-rfck
-lisu
-tv
-lewd
-amibooru
-blankatlas
-mmballbusting
-sss
-legolamb
-goldengator
-r6gdrawfriends
-vivi
-twifanartsfw
-hololive
-vglobby
-jaypee
-melanin
-dollstuffing
-orb
-min
-mjg
-cloppers
-townofgravityfalls
-brown
-enacdoa
-daifuku
-straponff
-keyofnik
-osc
-konan
-girlsfeet
-hybreedsgeneral
-sr
-mono
-riskofrain
-neovb
-ffsr
-
diff --git a/app.py b/app.py index b04031b..9a0bc96 100644 --- a/app.py +++ b/app.py @@ -6,49 +6,31 @@ # @File Name: app.py -import os import time -from typing import Any from flask import Flask from flask import Response from flask import request from flask import make_response -from flask import send_from_directory +from flask import render_template from gevent import pywsgi from bin.utils.error import ErrorProcess +from bin.utils.features import Features from bin.utils.view import view_template from bin.utils.logger import logger -from bin.utils.packing_logs import make_targz from bin.utils.settings import Settings -from bin.db.db import SQLite - -app = Flask(__name__, static_url_path='') -app.config['JSON_SORT_KEYS'] = False # 设置JSON消息不根据字母顺序重新排序 -app.config['JSON_AS_ASCII'] = False # 设置JSON消息显示中文 conf = Settings() +if conf.type == 'MySQL': + from bin.db.db import MySQL as db +else: + from bin.db.db import SQLite as db -def build_page(name: str, length: int, theme: str) -> list[bool or Response] or list[bool or Any] or list[bool or str]: - """ - 渲染最终的页面 - :param theme: - :param name: - :param length: - :return: - """ - count = SQLite().fetch_data(name) - if len(str(count)) > length: # 判断在数据库内的长度是否超过了设定的(或预设的)长度 - return [False, ErrorProcess().too_lang_to_count(name)] - if 7 <= length <= 10: # 判断设定的长度是否超过阈值 - zero_count = '0' * (length - len(str(count))) + str(count) - status, template = view_template(theme, length, name, zero_count) - if status is True: - return [True, template] - else: - return [False, 'BadTheme'] - else: - return [False, 'BadLength'] +app = Flask(__name__, + static_folder='bin/static', + template_folder='bin/templates') +app.config['JSON_SORT_KEYS'] = False # 设置JSON消息不根据字母顺序重新排序 +app.config['JSON_AS_ASCII'] = False # 设置JSON消息显示中文 @app.before_request @@ -58,100 +40,47 @@ def requests_log() -> None: :return: """ if request.path != '/favicon.ico': # 不记录favicon.ico的请求记录 - logger.info(f'{request.host} {request.method} {request.full_path}') - - file_list = os.listdir('./static/cache') - file_list.remove('.gitkeep') - for i in file_list: - os.remove(f'./static/cache/{i}') - - origin_log_list = os.listdir('./bin/log') - origin_log_list.remove('.gitkeep') - if len(origin_log_list) > 100: - for d in origin_log_list: - try: - os.remove(f'./bin/log/{d}') - except PermissionError: - pass + logger.info(f'{request.remote_addr} {request.method} {request.base_url}') -@app.route('/db', methods=['GET', 'POST']) -def export_db(): - """ - 导出数据库 - :return: - """ - dir_path = os.path.join(app.root_path, 'bin/db') - return send_from_directory(dir_path, 'data.db', as_attachment=True) - - -@app.route('/log', methods=['GET', 'POST']) -def view_log() -> Response: - """ - 下载日志 - :return: - """ - make_targz() # 打包tar.gz 文件 - log_file = f'{time.strftime("%Y-%m-%d %H")}.tar.gz' - logger.warning(f'{request.host} {request.method} {request.path} -> Packed log files: {log_file}') - dir_path = os.path.join(app.root_path, 'static/cache') - return send_from_directory(dir_path, log_file, as_attachment=True) - - -@app.route('/get', methods=['GET', 'POST']) # 允许 GET 和 POST 方法 -def main() -> Response or str: +@app.route('/get/', methods=['GET', 'POST']) # 允许 GET 和 POST 方法 +def main(name) -> Response or str: """ API 页面函数 :return: """ args = request.args - name = str(args.get('name')).replace('None', 'null') theme = args.get('theme') - length = str(args.get('length')).replace('None', '7') - try: - length = int(length) - except ValueError: - return ErrorProcess().error_length(length) - if theme == 'ls': - return ErrorProcess().get_theme_list() - if name and name != 'null': - if not theme: - theme = conf.default_style # 设置默认主题 - build_page_result = build_page(name, length, theme) # 开始处理整体页面 - if build_page_result[0]: - response = make_response(build_page_result[1]) # 设置响应体 和 响应头 - response.headers['Content-Type'] = 'image/svg+xml; charset=utf-8' - # 防止浏览器和markdown编辑器缓存图片 - response.headers['cache-control'] = 'max-age=0, no-cache, no-store, must-revalidate' - response.headers['date'] = time.ctime() - return response - elif build_page_result[1] == 'BadLength': # 输入的长度错误 - return ErrorProcess().error_length(length) - elif build_page_result[1] == 'BadTheme': # 输入的主题错误 - return ErrorProcess().error_theme(theme) - else: # 长度过长无法计数重置数据库内的已有数据 - logger.critical(f'用户: {name} 数据已被重置') - return build_page_result[1] + length = args.get('length') + if not bool(theme): # 判断主题是否存在查询参数内如果不存在则使用配置文件内的默认主题 + theme = conf.default_style + elif theme == 'ls': + return Features(db).theme_list() + if not bool(length): + length = 7 + if not db().exists_name(name): + db().insert(name) + count = db().fetch(name) + themes = db().fetching_table(theme) + if not len(themes): + return ErrorProcess(db).theme_error(theme) + if 7 <= int(length) <= 10: # 限定自定义长度阈值 + view_number = '0' * (int(length) - len(str(count[1]))) + str(count[1]) + response = make_response(view_template(theme, int(length), name, view_number, db)) # 设置响应体 和 响应头 + response.headers['Content-Type'] = 'image/svg+xml; charset=utf-8' + response.headers['cache-control'] = 'max-age=0, no-cache, no-store, must-revalidate' + return response else: - return ErrorProcess().arg_not_be_full() - - -@app.route('/favicon.ico', methods=['GET', 'POST']) -def favicon() -> Response: - """ - 主页图标 - :return: - """ - return app.send_static_file('favicon.ico') + return ErrorProcess(db).length_error(length) @app.route('/', methods=['GET', 'POST']) -def index() -> Response: +def home() -> str: """ - 索引页面 + 主页面 :return: """ - return app.send_static_file('index.html') + return render_template('index.html', remote_address=request.remote_addr) if __name__ == '__main__': diff --git a/bin/conf/config.yml b/bin/conf/config.yml index c2e34db..a935772 100644 --- a/bin/conf/config.yml +++ b/bin/conf/config.yml @@ -13,7 +13,7 @@ view: database: # 数据库类型 # 可选 'SQLite' /'MySQL'/ -> 暂未开发 - type: SQLite + type: "SQLite" SQLite: # 数据库的路径, # 需要从app.py文件所在目录为工作目录 diff --git a/bin/db/db.py b/bin/db/db.py index eb64b40..f6ebbad 100644 --- a/bin/db/db.py +++ b/bin/db/db.py @@ -7,116 +7,289 @@ import sqlite3 -from typing import Any +import pymysql class SQLite: """操作SQLite数据库""" - def __init__(self, path: str = './bin/db/data.db'): + def __init__(self, + path: str = './bin/db/data.db' + ) -> None: """ - 初始化SQLite类 + 初始化SQLite对象 + 完成后会自动提交, 自动关闭 :param path: 数据库路径 """ - self.path = path + self.__path = path + self.__conn = sqlite3.connect(self.__path) + self.__cursor = self.__conn.cursor() - def insert_data(self, name: str) -> None: + def __del__(self) -> None: + """ + 自动提交 + 自动关闭连接 + :return: + """ + self.__conn.commit() + self.__cursor.close() + self.__conn.close() + + @property + def show_tables(self) -> list: + """ + 列出所有在数据库内的表 + :return: + """ + self.__cursor.execute('select * from sqlite_master where type="table"') + tables = self.__cursor.fetchall() + lst = [] + for table in tables: + lst.append(table[1]) + del tables + return lst + + def exists_name(self, name: str) -> bool: + """ + 判断当前名称是否在数据库内 + 调用self.fetch()方法 + :param name: + :return: + """ + status = self.fetch(name, True) + if status == (): + return False + else: + return True + + def exists_table(self, table: str) -> bool: + """ + 判断表是否在数据库内 + 调用self.fetching_table()方法 + :param table: + :return: + """ + tables = self.show_tables + if table in tables: + return True + else: + return False + + def insert(self, name: str, times: int = 0) -> bool: """ 插入数据 :param name: + :param times: :return: """ - conn = sqlite3.connect(self.path, check_same_thread=False) - cursor = conn.cursor() - try: - cursor.execute('insert into ReqCount values(?, ?)', (name, 1)) - conn.commit() - finally: - cursor.close() - conn.close() + self.__cursor.execute( + 'insert into reqcount (name, times) values("%(name)s", %(times)s)' % {'name': name, 'times': times}) + return True - def fetch_data(self, name: str) -> int: + def delete(self, name: str) -> bool: """ - 获取数据 + 删除数据 + 暂时不会用到此接口 :param name: :return: """ - conn = sqlite3.connect(self.path, check_same_thread=False) - cursor = conn.cursor() - try: - cursor.execute('select * from ReqCount') - conn.commit() - data = cursor.fetchall() + self.__cursor.execute('delete from reqcount where name="%(name)s"' % {'name': name}) + return True - temp_dict = {} - for k, v in data: # 遍历数据将元组数据转换为字典类型 - temp_dict.setdefault(k, []).append(v) - for i, c in zip(temp_dict.keys(), temp_dict.values()): - temp_dict[i] = c[0] + def fetch(self, name: str, is_check: bool = False) -> tuple: + """ + 抓取数据 + :param name: + :param is_check: + :return: + """ + self.__cursor.execute('select * from reqcount where name="%(name)s"' % {'name': name}) + data = self.__cursor.fetchall() + if not is_check: + self.update(name, data[0][1]) + if len(data): + return data[0] + else: + return tuple(data) - if name in temp_dict.keys(): - count = temp_dict[name] # 获取原数字 为 整型 - self.update_data(name, count) - return count - else: - # 新建用户数据 - self.insert_data(name) - return 0 - finally: - cursor.close() - conn.close() - - def update_data(self, name: str, times: int) -> None: + def update(self, name: str, times: int) -> bool: """ 更新数据 :param name: :param times: :return: """ - conn = sqlite3.connect(self.path, check_same_thread=False) - cursor = conn.cursor() - try: - times += 1 - cursor.execute('update ReqCount set times=? where name=?', (times, name)) - conn.commit() - finally: - cursor.close() - conn.close() + self.__cursor.execute( + 'update reqcount set times=%(times)s where name="%(name)s"' % {'times': times + 1, 'name': name}) + return True - def fetch_table(self) -> list: + def fetching_table(self, table: str) -> list[dict]: """ - 返回已有主题列表 + 抓取主题表的数据 + :param table: :return: """ - conn_temp = sqlite3.connect(self.path, check_same_thread=False) - cursor_temp = conn_temp.cursor() - try: + status = self.exists_table(table) + if status: + tables = self.__cursor.execute('select * from %(table)s' % {'table': table}) lst = [] - cursor_temp.execute("select * from sqlite_master where type='table'") - for i in cursor_temp.fetchall(): - lst.append(i[1]) + for data in tables: + lst.append({'index': data[0], + 'base64': data[1], + 'width': data[2], + 'height': data[3]}) + del tables return lst - finally: - cursor_temp.close() - conn_temp.close() + else: + return [] - def fetch_style_data(self, style: str) -> list[dict[str, Any]]: + +class MySQL: + """操作MySQL数据库""" + + def __init__(self, + host: str, + user: str, + pwd: str, + database: str + ) -> None: """ - 获取主题数据库内的数据 - :param style: + 初始化MySQL对象并创建一个连接 + 创建的连接会在执行完毕后自动提交以及自动关闭 + :param host: 数据库地址 + :param user: 数据库用户名 + :param pwd: 数据库密码 + :param database: 数据库名 + """ + self.__host = host + self.__user = user + self.__password = pwd + self.__database = database + self.__conn = pymysql.connect(user=self.__user, + password=self.__password, + host=self.__host, + database=self.__database) # 创建连接 + self.__cursor = self.__conn.cursor() + + def __del__(self): + """ + 自动提交 + 自动关闭连接 + :return: + """ + self.__conn.commit() + self.__cursor.close() + self.__conn.close() + + @property + def show_tables(self) -> list: + """ + 查询已有的表 + :return: + """ + self.__cursor.execute('show tables;') # 列出所有的表名 + tuple_tables = self.__cursor.fetchall() + # 将元组类型转换为列表 + tables = [] + for origin in tuple_tables: + tables.append(origin[0]) + del tuple_tables + return tables + + def exists_name(self, name: str): + """ + 判断是否存在于数据库内 + :param name: + :return: + """ + status = self.fetch(name, True) + if status == (): + return False + else: + return True + + def exists_table(self, table: str) -> bool: + """ + 判断表是否在数据库内 + :param table: + :return: + """ + tables = self.show_tables + if table in tables: + return True + else: + return False + + def insert(self, name: str, times: int = 0) -> bool: + """ + 插入数据 + :param name: + :param times: :return: """ - conn = sqlite3.connect(self.path, check_same_thread=False) - cursor = conn.cursor() try: - cursor.execute('select * from %(style_name)s' % {'style_name': style}) - data = cursor.fetchall() - data_set = [] - for i in data: - data_set.append({'index': i[0], 'base64': i[1], 'width': i[2], 'height': i[3]}) - return data_set - finally: - cursor.close() - conn.close() + self.__cursor.execute( + 'insert into reqcount(name, times) values("%(name)s", %(times)s);' % {'name': name, 'times': times}) + return True + except pymysql.err.IntegrityError: + return False + + def delete(self, name: str) -> bool: + """ + 删除数据 + 暂时不会用到此接口 + :param name: + :return: + """ + self.__cursor.execute('delete from reqcount where name="%(name)s";' % {'name': name}) + return True + + def fetch(self, name: str, is_check: bool = False) -> tuple: + """ + 抓取数据 + :param name: + :param is_check: + :return: + """ + self.__cursor.execute('select * from reqcount where name="%(name)s";' % {'name': name}) + data = self.__cursor.fetchall() + if not is_check: # 条件适用于使用self.exists_name检查时不将数据库的计数加一 + self.update(name, data[0][1]) + if data == (): + return () + else: + return data[0] + + def update(self, name: str, times: int) -> bool: + """ + 更改数据 + :param name: + :param times: + :return: + """ + self.__cursor.execute( + 'update reqcount set times="%(times)s" where name="%(name)s"";' % {'times': times + 1, 'name': name}) + return True + + def fetching_table(self, table: str) -> list: + """ + 抓取主题表内的数据 + :param table: + :return: + """ + self.__cursor.execute('select * from %(table)s' % {'table': table}) + datas = self.__cursor.fetchall() + lst = [] + for i in datas: + lst.append({'index': i[0], + 'base64': i[1], + 'width': i[2], + 'height': i[3]} + ) # 向空列表内添加抓取到的数据 -> 将元组数据转换为列表 + + del datas + return lst +__all__ = ['SQLite', 'MySQL'] + diff --git a/static/cache/.gitkeep b/bin/static/cache/.gitkeep similarity index 100% rename from static/cache/.gitkeep rename to bin/static/cache/.gitkeep diff --git a/static/favicon.ico b/bin/static/favicon.ico similarity index 100% rename from static/favicon.ico rename to bin/static/favicon.ico diff --git a/bin/templates/index.html b/bin/templates/index.html new file mode 100644 index 0000000..cb381e8 --- /dev/null +++ b/bin/templates/index.html @@ -0,0 +1,47 @@ + + + + + Request Counter - Index + + + + + + +
+
+
+ 看到这句话就说明程序正常运行啦!! 查看文档 +
+ 服务端使用Flask开发没有使用异步编程 +
+ 点击查看本地部署示例 +
+ 点击查看已部署好的调用示例 +
+ 注: 调用支持POST 和 GET 方法请求 +
+
+ 项目开源协议: Apache-2.0 即: +
+ 你可以直接使用该项目提供的功能, 无需任何授权 +
+ 你可以在注明来源版权信息的情况下对源代码进行任意分发和修改以及衍生 +
+
+ + 你的IP地址为: {{ remote_address }} +
+ + \ No newline at end of file diff --git a/templates/view.html b/bin/templates/view.html similarity index 65% rename from templates/view.html rename to bin/templates/view.html index 703e1f3..bd8655b 100644 --- a/templates/view.html +++ b/bin/templates/view.html @@ -4,8 +4,8 @@ {{ title }} {% for value in context %} - + {% endfor %} diff --git a/bin/tests/MySQLSET/MySQL.py b/bin/tests/MySQL.py similarity index 91% rename from bin/tests/MySQLSET/MySQL.py rename to bin/tests/MySQL.py index 497333a..951926b 100644 --- a/bin/tests/MySQLSET/MySQL.py +++ b/bin/tests/MySQL.py @@ -8,12 +8,9 @@ from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker -from sqlalchemy.ext.declarative import declarative_base -from tables import * # 导入所有的主题表模型 +from models import * # 导入所有的主题表模型 from typing import List, Tuple -Base = declarative_base() - class MySQL: """使用SQLAlchemy进行的MySQL数据库操作""" @@ -50,8 +47,9 @@ class MySQL: self.database = database self.charset = charset self.engine = create_engine( - f'mysql+mysqlconnector://{self.user}:{self.password}@{self.host}:{self.port}/{self.database}') # 连接到数据库 + f'mysql+pymysql://{self.user}:{self.password}@{self.host}:{self.port}/{self.database}') # 连接到数据库 self.Session = sessionmaker(bind=self.engine) # 创建引擎 + self.Base = Base def __del__(self): """ @@ -101,7 +99,7 @@ class MySQL: """ data = self.session.query(ReqCount).filter(ReqCount.name == name).all() for i in data: - print(i.times) + return i.times def fetchall(self) -> List[Tuple]: """ @@ -126,3 +124,7 @@ class MySQL: for tup in tables: table_list.append((tup.k, tup.v, tup.w, tup.h)) return table_list + + def create(self): + self.Base.metadata.create_all(self.engine) + diff --git a/bin/tests/MySQLSET/__init__.py b/bin/tests/MySQLSET/__init__.py deleted file mode 100644 index adb6151..0000000 --- a/bin/tests/MySQLSET/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env python3 -# -- coding:utf-8 -- -# @Author: markushammered@gmail.com -# @Development Tool: PyCharm -# @Create Time: 2022/2/26 -# @File Name: __init__.py.py - - diff --git a/bin/tests/MySQL_.py b/bin/tests/MySQL_.py new file mode 100644 index 0000000..3460329 --- /dev/null +++ b/bin/tests/MySQL_.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +# -- coding:utf-8 -- +# @Author: markushammered@gmail.com +# @Development Tool: PyCharm +# @Create Time: 2022/2/27 +# @File Name: MySQL_.py + + +import pymysql + + +class MySQL: + """操作MySQL数据库""" + + def __init__(self, + host: str, + user: str, + pwd: str, + database: str + ) -> None: + """ + 初始化MySQL对象并创建一个连接 + 创建的连接会在执行完毕后自动提交以及自动关闭 + :param host: 数据库地址 + :param user: 数据库用户名 + :param pwd: 数据库密码 + :param database: 数据库名 + """ + self.__host = host + self.__user = user + self.__password = pwd + self.__database = database + self.__conn = pymysql.connect(user=self.__user, + password=self.__password, + host=self.__host, + database=self.__database) # 创建连接 + self.__cursor = self.__conn.cursor() + + def __del__(self): + """ + 自动提交 + 自动关闭连接 + :return: + """ + self.__conn.commit() + self.__cursor.close() + self.__conn.close() + + @property + def show_tables(self) -> list: + """ + 查询已有的表 + :return: + """ + self.__cursor.execute('show tables;') # 列出所有的表名 + tuple_tables = self.__cursor.fetchall() + # 将元组类型转换为列表 + tables = [] + for origin in tuple_tables: + tables.append(origin[0]) + del tuple_tables + return tables + + def exists_name(self, name: str): + """ + 判断是否存在于数据库内 + :param name: + :return: + """ + status = self.fetch(name) + if status == (): + return False + else: + return True + + def exists_table(self, table: str) -> bool: + """ + 判断表是否在数据库内 + :param table: + :return: + """ + tables = self.show_tables + if table in tables: + return True + else: + return False + + def insert(self, name: str, times: int = 0) -> bool: + """ + 插入数据 + :param name: + :param times: + :return: + """ + try: + self.__cursor.execute( + 'insert into reqcount(name, times) values("%(name)s", %(times)s);' % {'name': name, 'times': times}) + return True + except pymysql.err.IntegrityError: + return False + + def delete(self, name: str) -> bool: + """ + 删除数据 + :param name: + :return: + """ + self.__cursor.execute('delete from reqcount where name="%(name)s";' % {'name': name}) + return True + + def fetch(self, name: str) -> bool or tuple: + """ + 抓取数据 + :param name: + :return: + """ + self.__cursor.execute('select * from reqcount where name="%(name)s";' % {'name': name}) + data = self.__cursor.fetchall() + if data == (): + return False + else: + return data[0] + + def update(self, name: str, times: int) -> bool: + """ + 更改数据 + :param name: + :param times: + :return: + """ + self.__cursor.execute( + 'update reqcount set times="%(times)s where name="%(name)s"";' % {'times': times, 'name': name}) + return True + + def fetching_table(self, table: str) -> list: + """ + 抓取主题表内的数据 + :param table: + :return: + """ + self.__cursor.execute('select * from %(table)s' % {'table': table}) + datas = self.__cursor.fetchall() + lst = [] + for i in datas: + lst.append({'k': i[0], + 'v': i[1], + 'w': i[2], + 'h': i[3]} + ) # 向空列表内添加抓取到的数据 -> 将元组数据转换为列表 + + del datas + return lst + + +__all__ = ['MySQL'] \ No newline at end of file diff --git a/bin/tests/SQLite_.py b/bin/tests/SQLite_.py new file mode 100644 index 0000000..c5a3acd --- /dev/null +++ b/bin/tests/SQLite_.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python3 +# -- coding:utf-8 -- +# @Author: markushammered@gmail.com +# @Development Tool: PyCharm +# @Create Time: 2022/2/27 +# @File Name: SQLite_.py + + +import sqlite3 + + +class SQLite: + """操作SQLite数据库""" + + def __init__(self, + path: str = './bin/db/data.db' + ) -> None: + """ + 初始化SQLite对象 + :param path: 数据库路径 + """ + self.__path = path + self.__conn = sqlite3.connect(self.__path) + self.__cursor = self.__conn.cursor() + + def __del__(self) -> None: + """ + 自动提交 + 自动关闭连接 + :return: + """ + self.__conn.commit() + self.__cursor.close() + self.__conn.close() + + @property + def show_tables(self) -> list: + """ + 列出所有在数据库内的表 + :return: + """ + self.__cursor.execute('select * from sqlite_master where type="table"') + tables = self.__cursor.fetchall() + lst = [] + for table in tables: + lst.append(table[1]) + del tables + return lst + + def exist_name(self, name: str) -> bool: + """ + 判断当前名称是否在数据库内 + 调用fetch方法判断 + :param name: + :return: + """ + status = self.fetch(name) + if status == (): + return False + else: + return True + + def exist_table(self, table: str) -> bool: + """ + 判断表是否在数据库内 + :param table: + :return: + """ + tables = self.show_tables + if table in tables: + return True + else: + return False + + def insert(self, name: str, times: int) -> bool: + """ + 插入数据 + :param name: + :param times: + :return: + """ + self.__cursor.execute( + 'insert into reqcount values(name="%(name)s", times=%(times)s)' % {'name': name, 'times': times}) + return True + + def delete(self, name: str) -> bool: + """ + 删除数据 + :param name: + :return: + """ + self.__cursor.execute('delete from reqcount where name="%(name)s"' % {'name': name}) + return True + + def fetch(self, name: str) -> tuple: + """ + 抓取数据 + :param name: + :return: + """ + self.__cursor.execute('select * from reqcount where name="%(name)s"' % {'name': name}) + data = self.__cursor.fetchall() + if len(data): + return data[0] + else: + return tuple(data) + + def update(self, name: str, times: int) -> bool: + """ + 更新数据 + :param name: + :param times: + :return: + """ + self.__cursor.execute( + 'update reqcount set times=%(times)s where name="%(name)s"' % {'times': times, 'name': name}) + return True + + def fetching_table(self, table: str) -> list[dict]: + """ + 抓取主题表的数据 + :param table: + :return: + """ + status = self.exist_table(table) + if status: + tables = self.__cursor.execute('select * from %(table)s' % {'table': table}) + lst = [] + for data in tables: + lst.append({'index': data[0], + 'base64': data[1], + 'width': data[2], + 'height': data[3]}) + del tables + return lst + else: + return [] + + +sqlite = SQLite('../db/data.db') +print(sqlite.fetching_table('gelbooru')) diff --git a/bin/tests/MySQLSET/tables.py b/bin/tests/models.py similarity index 62% rename from bin/tests/MySQLSET/tables.py rename to bin/tests/models.py index 96bcd00..3c8ec50 100644 --- a/bin/tests/MySQLSET/tables.py +++ b/bin/tests/models.py @@ -9,7 +9,7 @@ from sqlalchemy import Column from sqlalchemy import Integer from sqlalchemy import String -from sqlalchemy import Text +from sqlalchemy import VARCHAR from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() @@ -20,351 +20,351 @@ Base = declarative_base() class ReqCount(Base): """计数器数据库模型""" - __tablename__ = 'ReqCount' + __tablename__ = 'reqcount' name = Column(String(20), primary_key=True) # 名称 times = Column(Integer()) # 次数 class gelbooru(Base): __tablename__ = 'gelbooru' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class moebooru(Base): __tablename__ = 'moebooru' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class g(Base): __tablename__ = 'g' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class cripple(Base): __tablename__ = 'cripple' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class blacked(Base): __tablename__ = 'blacked' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class rule34(Base): __tablename__ = 'rule34' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class steambanner(Base): __tablename__ = 'steambanner' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class lefty(Base): __tablename__ = 'lefty' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class crewbooru(Base): __tablename__ = 'crewbooru' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class sthg(Base): __tablename__ = 'sthg' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class rfck(Base): __tablename__ = 'rfck' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class lisu(Base): __tablename__ = 'lisu' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class tv(Base): __tablename__ = 'tv' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class lewd(Base): __tablename__ = 'lewd' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class amibooru(Base): __tablename__ = 'amibooru' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class blankatlas(Base): __tablename__ = 'blankatlas' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class mmballbusting(Base): __tablename__ = 'mmballbusting' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class sss(Base): __tablename__ = 'sss' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class legolamb(Base): __tablename__ = 'legolamb' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class goldengator(Base): __tablename__ = 'goldengator' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class r6gdrawfriends(Base): __tablename__ = 'r6gdrawfriends' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class vivi(Base): __tablename__ = 'vivi' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class twifanartsfw(Base): __tablename__ = 'twifanartsfw' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class hololive(Base): __tablename__ = 'hololive' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class vglobby(Base): __tablename__ = 'vglobby' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class jaypee(Base): __tablename__ = 'jaypee' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class melanin(Base): __tablename__ = 'melanin' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class orb(Base): __tablename__ = 'orb' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class min(Base): __tablename__ = 'min' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class mjg(Base): __tablename__ = 'mjg' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class cloppers(Base): __tablename__ = 'cloppers' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class townofgravityfalls(Base): __tablename__ = 'townofgravityfalls' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class brown(Base): __tablename__ = 'brown' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class enacdoa(Base): __tablename__ = 'enacdoa' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class daifuku(Base): __tablename__ = 'daifuku' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class osc(Base): __tablename__ = 'osc' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class girlsfeet(Base): __tablename__ = 'girlsfeet' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class hybreedsgeneral(Base): __tablename__ = 'hybreedsgeneral' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class sr(Base): __tablename__ = 'sr' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class mono(Base): __tablename__ = 'mono' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class riskofrain(Base): __tablename__ = 'riskofrain' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class neovb(Base): __tablename__ = 'neovb' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) class ffsr(Base): __tablename__ = 'ffsr' - k = Column(Text, primary_key=True) - v = Column(Text) + k = Column(VARCHAR(500), primary_key=True) + v = Column(VARCHAR(500)) w = Column(Integer()) h = Column(Integer()) @@ -373,4 +373,4 @@ __all__ = ['ReqCount', 'gelbooru', 'moebooru', 'g', 'cripple', 'blacked', 'rule3 'sthg', 'rfck', 'lisu', 'tv', 'lewd', 'amibooru', 'blankatlas', 'mmballbusting', 'sss', 'legolamb', 'goldengator', 'r6gdrawfriends', 'vivi', 'twifanartsfw', 'hololive', 'vglobby', 'jaypee', 'melanin', 'orb', 'min', 'mjg', 'cloppers', 'townofgravityfalls', 'brown', 'enacdoa', 'daifuku', 'osc', 'girlsfeet', - 'hybreedsgeneral', 'sr', 'mono', 'riskofrain', 'neovb', 'ffsr'] + 'hybreedsgeneral', 'sr', 'mono', 'riskofrain', 'neovb', 'ffsr', 'Base'] diff --git a/bin/utils/error.py b/bin/utils/error.py index eaebe8b..19cdb84 100644 --- a/bin/utils/error.py +++ b/bin/utils/error.py @@ -9,74 +9,54 @@ from typing import Optional from flask import jsonify from flask import Response -from bin.db.db import SQLite from bin.utils.logger import logger class ErrorProcess: """处理错误的页面""" - def __init__(self) -> None: - self.msg_template = {'code': -2, - 'msg': Optional[str], - 'data': Optional[list]} - def get_theme_list(self) -> Response: + def __init__(self, db) -> None: """ - 直接获取可选主题 - :return: + 初始化 + :param db: """ - logger.debug('获取主题') - table_list = SQLite().fetch_table() - self.msg_template['code'] = 200 - self.msg_template['msg'] = '当前已保存到数据库的主题如下' - self.msg_template['data'] = table_list - return jsonify(self.msg_template) + self.db = db # 数据库对象 + self.response = {'code': Optional[int], + 'msg': Optional[str], + 'data': Optional[list]} - def error_theme(self, theme: str) -> Response: + def theme_error(self, theme: str) -> Response: """ 错误的主题 :param theme: :return: """ logger.debug('错误的主题') - table_list = SQLite().fetch_table() - self.msg_template['code'] = -2 - self.msg_template['msg'] = f'错误的主题: {theme}. 以下是已保存的主题' - self.msg_template['data'] = table_list - return jsonify(self.msg_template) + table_list = self.db().show_tables + self.response['code'] = -2 + self.response['msg'] = f'错误的主题: {theme}. 以下是已保存的主题' + self.response['data'] = table_list + return jsonify(self.response) - def error_length(self, length: int or str) -> Response: + def length_error(self, length: int or str) -> Response: """ 数值太长显示此页面 :param length: :return: """ - logger.debug('错误的长度') - self.msg_template['code'] = -2 - self.msg_template['msg'] = f'错误的长度: {length}' - self.msg_template['data'] = None - return jsonify(self.msg_template) + self.response['code'] = -2 + self.response['msg'] = f'错误的长度: {length}' + self.response['data'] = [] + return jsonify(self.response) - def too_lang_to_count(self, name: str) -> Response: + def count_error(self, name: str) -> Response: """ 数据过长重置数据 :param name: :return: """ - logger.debug('超出计数器最大计数限制') - SQLite().update_data(name, 0) - self.msg_template['code'] = 200 - self.msg_template['msg'] = '当前长度已超过最大可计数范围. 已将此名称的计数器重置为零' - self.msg_template['data'] = None - return jsonify(self.msg_template) - - def arg_not_be_full(self) -> Response: - """ - 参数不完整 - :return: - """ - logger.debug('参数不完整') - self.msg_template['code'] = -2 - self.msg_template['msg'] = '参数填写错误或填写不完整' - self.msg_template['data'] = None - return jsonify(self.msg_template) + self.db().update(name, 0) + self.response['code'] = 200 + self.response['msg'] = '当前长度已超过最大可计数范围. 已将此名称的计数器重置为零' + self.response['data'] = [] + return jsonify(self.response) diff --git a/bin/utils/features.py b/bin/utils/features.py new file mode 100644 index 0000000..8a55f64 --- /dev/null +++ b/bin/utils/features.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# -- coding:utf-8 -- +# @Author: markushammered@gmail.com +# @Development Tool: PyCharm +# @Create Time: 2022/2/28 +# @File Name: features.py + + +from typing import Optional +from flask import jsonify +from flask import Response + + +class Features: + """特殊操作""" + + def __init__(self, db) -> None: + """ + 初始化 + :param db: + """ + self.db = db + self.response = {'code': Optional[int], + 'msg': Optional[str], + 'data': Optional[list]} + + def theme_list(self) -> Response: + """ + 读取已有数据库并返回一个列表 + :return: + """ + table_list = self.db().show_tables + self.response['code'] = 200 + self.response['msg'] = '当前已保存到数据库的主题如下' + self.response['data'] = table_list + return jsonify(self.response) diff --git a/bin/utils/packing_logs.py b/bin/utils/packing_logs.py deleted file mode 100644 index 8f25595..0000000 --- a/bin/utils/packing_logs.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python3 -# -- coding:utf-8 -- -# @Author: markushammered@gmail.com -# @Development Tool: PyCharm -# @Create Time: 2022/2/18 -# @File Name: packing_logs.py - - -import os -import time -import tarfile - - -def make_targz(): - """ - 打包为tar.gz - 压缩文件 - :return: - """ - output_dir = f'./static/cache/{time.strftime("%Y-%m-%d %H")}.tar.gz' - tar = tarfile.open(output_dir, 'w:gz') - for root, dir, files in os.walk('./bin/log'): - for file in files: - pathfile = os.path.join(root, file) - tar.add(pathfile) - tar.close() - - -__all__ = ['make_targz'] \ No newline at end of file diff --git a/bin/utils/view.py b/bin/utils/view.py index 58b1b39..cb94ec0 100644 --- a/bin/utils/view.py +++ b/bin/utils/view.py @@ -7,72 +7,69 @@ from flask import render_template -from bin.db.db import SQLite -def view_template(style: str, length: int, name: str, count: str) -> str or tuple[bool, str]: +def view_template(style: str, length: int, name: str, count: str, DB) -> str or tuple[bool, str]: """ 渲染模板 - :param count: - :param name: - :param length: :param style: + :param length: + :param name: + :param count: + :param DB: :return: """ - if style not in SQLite().fetch_table(): # 选择的主题不在数据库内 - return [False, 'BadLength'] - origin_data = SQLite().fetch_style_data(style) # 获取数据库内的数据 + datas = DB().fetching_table(style) context = [] - if count != '0000000000': - for i in count: # 通过elif语句依次判断数字 - if i == '0': - context.append({'base64': origin_data[0]['base64'], - 'width': origin_data[0]['width'], - 'height': origin_data[0]['height']}) - elif i == '1': - context.append({'base64': origin_data[1]['base64'], - 'width': origin_data[1]['width'], - 'height': origin_data[1]['height']}) - elif i == '2': - context.append({'base64': origin_data[2]['base64'], - 'width': origin_data[2]['width'], - 'height': origin_data[2]['height']}) - elif i == '3': - context.append({'base64': origin_data[3]['base64'], - 'width': origin_data[3]['width'], - 'height': origin_data[3]['height']}) - elif i == '4': - context.append({'base64': origin_data[4]['base64'], - 'width': origin_data[4]['width'], - 'height': origin_data[4]['height']}) - elif i == '5': - context.append({'base64': origin_data[5]['base64'], - 'width': origin_data[5]['width'], - 'height': origin_data[5]['height']}) - elif i == '6': - context.append({'base64': origin_data[6]['base64'], - 'width': origin_data[6]['width'], - 'height': origin_data[6]['height']}) - elif i == '7': - context.append({'base64': origin_data[7]['base64'], - 'width': origin_data[7]['width'], - 'height': origin_data[7]['height']}) - elif i == '8': - context.append({'base64': origin_data[8]['base64'], - 'width': origin_data[8]['width'], - 'height': origin_data[8]['height']}) - elif i == '9': - context.append({'base64': origin_data[9]['base64'], - 'width': origin_data[9]['width'], - 'height': origin_data[9]['height']}) + for i in count: + if i == '0': + context.append({'base64': datas[0]['base64'], + 'width': datas[0]['width'], + 'height': datas[0]['height']}) + elif i == '1': + context.append({'base64': datas[1]['base64'], + 'width': datas[1]['width'], + 'height': datas[1]['height']}) + elif i == '2': + context.append({'base64': datas[2]['base64'], + 'width': datas[2]['width'], + 'height': datas[2]['height']}) + elif i == '3': + context.append({'base64': datas[3]['base64'], + 'width': datas[3]['width'], + 'height': datas[3]['height']}) + elif i == '4': + context.append({'base64': datas[4]['base64'], + 'width': datas[4]['width'], + 'height': datas[4]['height']}) + elif i == '5': + context.append({'base64': datas[5]['base64'], + 'width': datas[5]['width'], + 'height': datas[5]['height']}) + elif i == '6': + context.append({'base64': datas[6]['base64'], + 'width': datas[6]['width'], + 'height': datas[6]['height']}) + elif i == '7': + context.append({'base64': datas[7]['base64'], + 'width': datas[7]['width'], + 'height': datas[7]['height']}) + elif i == '8': + context.append({'base64': datas[8]['base64'], + 'width': datas[8]['width'], + 'height': datas[8]['height']}) + elif i == '9': + context.append({'base64': datas[9]['base64'], + 'width': datas[9]['width'], + 'height': datas[9]['height']}) for p, i in zip(context, range(0, length)): p['position'] = i * p['width'] # 设置每张图片对应的位置 - general_width = origin_data[0]['width'] * length # 计算出图片总长度 - general_height = origin_data[0]['height'] # 总宽度 + general_width = datas[0]['width'] * length # 计算出图片总长度 + general_height = datas[0]['height'] # 总宽度 - return True, render_template('view.html', + return render_template('view.html', context=context, title=name, general_height=general_height, diff --git a/requirements.txt b/requirements.txt index aa3de5b..e7e0405 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ -Flask~=2.0.2 +Flask~=0.12.2 requests~=2.27.1 gevent~=21.12.0 gunicorn~=20.1.0 colorlog~=6.6.0 -PyYAML~=6.0 \ No newline at end of file +PyYAML~=6.0 +PyMySQL~=1.0.2 \ No newline at end of file diff --git a/static/index.html b/static/index.html deleted file mode 100644 index 377387d..0000000 --- a/static/index.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - Request Counter - Index - Flask - - - -
-
-
- 看到这句话就说明程序正常运行啦!! 查看文档 -
- 服务端使用Flask开发没有使用异步编程 -
- 点击查看本地部署示例 -
- 点击查看已部署好的调用示例 -
- 注: 调用支持POST 和 GET 方法请求 -
-
- 项目开源协议: Apache-2.0 即: -
- 你可以直接使用该项目提供的功能, 无需任何授权 -
- 你可以在注明来源版权信息的情况下对源代码进行任意分发和修改以及衍生 -
-
-

效果是这样的↓

- example -
- 默认主题为 lewd -
-
- - \ No newline at end of file