mirror of
https://github.com/MeoProject/lx-music-api-server.git
synced 2025-05-23 19:17:41 +08:00
feat: 便携版EXE
This commit is contained in:
parent
6409caf638
commit
49cb760d4d
5
.gitignore
vendored
5
.gitignore
vendored
@ -10,6 +10,11 @@ __pycache__/
|
|||||||
*.egg-info
|
*.egg-info
|
||||||
*.egg
|
*.egg
|
||||||
|
|
||||||
|
# pyinstaller
|
||||||
|
*.spec
|
||||||
|
dist
|
||||||
|
build
|
||||||
|
|
||||||
# project
|
# project
|
||||||
cache.db
|
cache.db
|
||||||
data.db
|
data.db
|
||||||
|
39
apis/.github/workflows/build_binary.yml
vendored
Normal file
39
apis/.github/workflows/build_binary.yml
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# this workflow using github actions to build a binary exe file for windows users
|
||||||
|
|
||||||
|
name: build Windows exe
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-exe:
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: setup python 3.11
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
|
||||||
|
- name: install pyinstaller
|
||||||
|
run: python -m pip install pyinstaller
|
||||||
|
|
||||||
|
- name: install dependencies
|
||||||
|
run: python -m pip install -r ./requirements.txt
|
||||||
|
|
||||||
|
- name: build exe
|
||||||
|
run: pyinstaller -F main.py
|
||||||
|
|
||||||
|
- name: rename
|
||||||
|
run: Rename-Item ./dist/main.exe ./dist/lx-music-api-server_$(git rev-parse --short HEAD).exe
|
||||||
|
|
||||||
|
- name: upload
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: lx-music-api-server
|
||||||
|
path: ./dist
|
@ -8,8 +8,8 @@
|
|||||||
# This file is part of the "lx-music-api-server" project.
|
# This file is part of the "lx-music-api-server" project.
|
||||||
# Do not edit except you konw what you are doing.
|
# Do not edit except you konw what you are doing.
|
||||||
|
|
||||||
from common.utils import require
|
|
||||||
from common.exceptions import FailedException
|
from common.exceptions import FailedException
|
||||||
|
from common.utils import require
|
||||||
from common import log
|
from common import log
|
||||||
from common import config
|
from common import config
|
||||||
from . import kw
|
from . import kw
|
||||||
@ -59,8 +59,15 @@ async def SongURL(source, songId, quality):
|
|||||||
'data': c['url'],
|
'data': c['url'],
|
||||||
}
|
}
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
logger.error(traceback.format_exc())
|
||||||
|
try:
|
||||||
func = require('apis.' + source).url
|
func = require('apis.' + source).url
|
||||||
|
except:
|
||||||
|
return {
|
||||||
|
'code': 1,
|
||||||
|
'msg': '未知的源: ' + source,
|
||||||
|
'data': None,
|
||||||
|
}
|
||||||
try:
|
try:
|
||||||
url = await func(songId, quality)
|
url = await func(songId, quality)
|
||||||
logger.debug(f'获取{source}_{songId}_{quality}成功,URL:{url}')
|
logger.debug(f'获取{source}_{songId}_{quality}成功,URL:{url}')
|
||||||
|
@ -14,32 +14,34 @@ import os
|
|||||||
import traceback
|
import traceback
|
||||||
import sys
|
import sys
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from .utils import unique_list, readfile
|
from .utils import readfile
|
||||||
from . import variable
|
from . import variable
|
||||||
from .log import log
|
from .log import log
|
||||||
# from dbutils.pooled_db import PooledDB
|
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
logger = log('config_manager')
|
||||||
|
|
||||||
# 创建线程本地存储对象
|
# 创建线程本地存储对象
|
||||||
local_data = threading.local()
|
local_data = threading.local()
|
||||||
|
|
||||||
|
|
||||||
def get_data_connection():
|
def get_data_connection():
|
||||||
# 检查线程本地存储对象是否存在连接对象,如果不存在则创建一个新的连接对象
|
# 检查线程本地存储对象是否存在连接对象,如果不存在则创建一个新的连接对象
|
||||||
if not hasattr(local_data, 'connection'):
|
if not hasattr(local_data, 'connection'):
|
||||||
local_data.connection = sqlite3.connect('data.db')
|
local_data.connection = sqlite3.connect('data.db')
|
||||||
return local_data.connection
|
return local_data.connection
|
||||||
|
|
||||||
|
|
||||||
# 创建线程本地存储对象
|
# 创建线程本地存储对象
|
||||||
local_cache = threading.local()
|
local_cache = threading.local()
|
||||||
|
|
||||||
|
|
||||||
def get_cache_connection():
|
def get_cache_connection():
|
||||||
# 检查线程本地存储对象是否存在连接对象,如果不存在则创建一个新的连接对象
|
# 检查线程本地存储对象是否存在连接对象,如果不存在则创建一个新的连接对象
|
||||||
if not hasattr(local_cache, 'connection'):
|
if not hasattr(local_cache, 'connection'):
|
||||||
local_cache.connection = sqlite3.connect('cache.db')
|
local_cache.connection = sqlite3.connect('cache.db')
|
||||||
return local_cache.connection
|
return local_cache.connection
|
||||||
|
|
||||||
logger = log('config_manager')
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigReadException(Exception):
|
class ConfigReadException(Exception):
|
||||||
pass
|
pass
|
||||||
@ -395,8 +397,11 @@ def initConfig():
|
|||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
# 创建一个表来存储缓存数据
|
# 创建一个表来存储缓存数据
|
||||||
cursor.execute(readfile(variable.workdir +
|
cursor.execute('''CREATE TABLE IF NOT EXISTS cache
|
||||||
'/common/sql/create_cache_db.sql'))
|
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
module TEXT NOT NULL,
|
||||||
|
key TEXT NOT NULL,
|
||||||
|
data TEXT NOT NULL)''')
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
@ -405,8 +410,9 @@ def initConfig():
|
|||||||
# 创建一个游标对象
|
# 创建一个游标对象
|
||||||
cursor2 = conn2.cursor()
|
cursor2 = conn2.cursor()
|
||||||
|
|
||||||
cursor2.execute(readfile(variable.workdir +
|
cursor2.execute('''CREATE TABLE IF NOT EXISTS data
|
||||||
'/common/sql/create_data_db.sql'))
|
(key TEXT PRIMARY KEY,
|
||||||
|
value TEXT)''')
|
||||||
|
|
||||||
conn2.close()
|
conn2.close()
|
||||||
|
|
||||||
@ -416,7 +422,7 @@ def initConfig():
|
|||||||
if (load_data() == {}):
|
if (load_data() == {}):
|
||||||
write_data('banList', [])
|
write_data('banList', [])
|
||||||
write_data('requestTime', {})
|
write_data('requestTime', {})
|
||||||
logger.debug('数据库内容为空,已写入默认值')
|
logger.info('数据库内容为空,已写入默认值')
|
||||||
|
|
||||||
|
|
||||||
def ban_ip(ip_addr, ban_time=-1):
|
def ban_ip(ip_addr, ban_time=-1):
|
||||||
|
@ -11,6 +11,10 @@
|
|||||||
import logging
|
import logging
|
||||||
import colorlog
|
import colorlog
|
||||||
import os
|
import os
|
||||||
|
import traceback
|
||||||
|
from pygments import highlight
|
||||||
|
from pygments.lexers import PythonLexer
|
||||||
|
from pygments.formatters import TerminalFormatter
|
||||||
from .utils import sanitize_filename
|
from .utils import sanitize_filename
|
||||||
from .variable import debug_mode, log_length_limit
|
from .variable import debug_mode, log_length_limit
|
||||||
|
|
||||||
@ -19,6 +23,13 @@ try:
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def highlight_error(error):
|
||||||
|
# 对堆栈跟踪进行语法高亮
|
||||||
|
highlighted_traceback = highlight(error, PythonLexer(), TerminalFormatter())
|
||||||
|
|
||||||
|
# 返回语法高亮后的堆栈跟踪字符串
|
||||||
|
return str(highlighted_traceback)
|
||||||
|
|
||||||
class flaskLogHelper(logging.Handler):
|
class flaskLogHelper(logging.Handler):
|
||||||
# werkzeug日志转接器
|
# werkzeug日志转接器
|
||||||
def __init__(self, custom_logger):
|
def __init__(self, custom_logger):
|
||||||
@ -45,7 +56,7 @@ class log:
|
|||||||
datefmt='%Y-%m-%d %H:%M:%S',
|
datefmt='%Y-%m-%d %H:%M:%S',
|
||||||
log_colors={
|
log_colors={
|
||||||
'DEBUG': 'cyan',
|
'DEBUG': 'cyan',
|
||||||
'INFO': 'green',
|
'INFO': 'white',
|
||||||
'WARNING': 'yellow',
|
'WARNING': 'yellow',
|
||||||
'ERROR': 'red',
|
'ERROR': 'red',
|
||||||
'CRITICAL': 'red,bg_white',
|
'CRITICAL': 'red,bg_white',
|
||||||
@ -120,6 +131,9 @@ class log:
|
|||||||
self._logger.warning(message)
|
self._logger.warning(message)
|
||||||
|
|
||||||
def error(self, message):
|
def error(self, message):
|
||||||
|
if (message.startswith('Traceback')):
|
||||||
|
self._logger.error('\n' + highlight_error(message))
|
||||||
|
else:
|
||||||
self._logger.error(message)
|
self._logger.error(message)
|
||||||
|
|
||||||
def critical(self, message):
|
def critical(self, message):
|
||||||
|
@ -37,7 +37,3 @@ def checklxmheader(lxm, url):
|
|||||||
return True
|
return True
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
exports = {
|
|
||||||
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
CREATE TABLE IF NOT EXISTS cache
|
|
||||||
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
module TEXT NOT NULL,
|
|
||||||
key TEXT NOT NULL,
|
|
||||||
data TEXT NOT NULL)
|
|
@ -1,3 +0,0 @@
|
|||||||
CREATE TABLE IF NOT EXISTS data
|
|
||||||
(key TEXT PRIMARY KEY,
|
|
||||||
value TEXT)
|
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
import platform
|
import platform
|
||||||
import binascii
|
import binascii
|
||||||
|
import builtins
|
||||||
import base64
|
import base64
|
||||||
import zlib
|
import zlib
|
||||||
import re
|
import re
|
||||||
@ -51,6 +52,9 @@ def require(module):
|
|||||||
index += 1
|
index += 1
|
||||||
return _module
|
return _module
|
||||||
|
|
||||||
|
def add_to_global_namespace(key, data):
|
||||||
|
setattr(builtins, key, data)
|
||||||
|
|
||||||
def sanitize_filename(filename):
|
def sanitize_filename(filename):
|
||||||
if platform.system() == 'Windows' or platform.system() == 'Cygwin':
|
if platform.system() == 'Windows' or platform.system() == 'Cygwin':
|
||||||
# Windows不合法文件名字符
|
# Windows不合法文件名字符
|
||||||
@ -129,3 +133,4 @@ class jsobject(dict):
|
|||||||
def __getattr__(self, UNUSED):
|
def __getattr__(self, UNUSED):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
add_to_global_namespace('require', require)
|
8
main.py
8
main.py
@ -29,8 +29,6 @@ from common import utils
|
|||||||
from common import lxsecurity
|
from common import lxsecurity
|
||||||
from apis import SongURL
|
from apis import SongURL
|
||||||
|
|
||||||
require = utils.require
|
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
return utils.format_dict_json({"code": 0, "msg": "success", "data": None}), 200
|
return utils.format_dict_json({"code": 0, "msg": "success", "data": None}), 200
|
||||||
@ -64,16 +62,20 @@ def _404(_):
|
|||||||
|
|
||||||
@app.before_request
|
@app.before_request
|
||||||
def check():
|
def check():
|
||||||
|
# nginx proxy header
|
||||||
if (request.headers.get("X-Real-IP")):
|
if (request.headers.get("X-Real-IP")):
|
||||||
request.remote_addr = request.headers.get("X-Real-IP")
|
request.remote_addr = request.headers.get("X-Real-IP")
|
||||||
|
# check ip
|
||||||
if (config.check_ip_banned(request.remote_addr)):
|
if (config.check_ip_banned(request.remote_addr)):
|
||||||
return utils.format_dict_json({"code": 1, "msg": "您的IP已被封禁", "data": None}), 403
|
return utils.format_dict_json({"code": 1, "msg": "您的IP已被封禁", "data": None}), 403
|
||||||
|
# update request time
|
||||||
config.updateRequestTime(request.remote_addr)
|
config.updateRequestTime(request.remote_addr)
|
||||||
|
# check host
|
||||||
if (config.read_config("security.allowed_host.enable")):
|
if (config.read_config("security.allowed_host.enable")):
|
||||||
if request.remote_host.split(":")[0] not in config.read_config("security.allowed_host.list"):
|
if request.remote_host.split(":")[0] not in config.read_config("security.allowed_host.list"):
|
||||||
if config.read_config("security.allowed_host.blacklist.enable"):
|
if config.read_config("security.allowed_host.blacklist.enable"):
|
||||||
config.ban_ip(request.remote_addr, int(config.read_config("security.allowed_host.blacklist.length")))
|
config.ban_ip(request.remote_addr, int(config.read_config("security.allowed_host.blacklist.length")))
|
||||||
return utils.format_dict_json({'code': 6, 'msg': '未找到您所请求的资源', 'data': None}), 404
|
return utils.format_dict_json({'code': 6, 'msg': '未找到您所请求的资源', 'data': None}), 404
|
||||||
|
|
||||||
|
# run
|
||||||
app.run(host=config.read_config('common.host'), port=config.read_config('common.port'))
|
app.run(host=config.read_config('common.host'), port=config.read_config('common.port'))
|
||||||
|
@ -3,3 +3,4 @@ pycryptodome
|
|||||||
ujson
|
ujson
|
||||||
requests
|
requests
|
||||||
colorlog
|
colorlog
|
||||||
|
pygments
|
||||||
|
Loading…
x
Reference in New Issue
Block a user