mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-06-07 11:45:35 +00:00
handle XDG_CONFIG_HOME specification ...
+ fix bug that caused duplicate artist color entries to db + check if app is windows (prep for windows build) + remove caribou migrations lib + rename all api blueprints to "api" + unregister child directories when customizing root dirs + misc
This commit is contained in:
parent
4e6e1f03dc
commit
bcc4873766
@ -5,17 +5,8 @@ This module combines all API blueprints into a single Flask app instance.
|
|||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
|
|
||||||
from app.api import (
|
from app.api import (album, artist, favorites, folder, imgserver, playlist,
|
||||||
album,
|
search, settings, track)
|
||||||
artist,
|
|
||||||
favorites,
|
|
||||||
folder,
|
|
||||||
playlist,
|
|
||||||
search,
|
|
||||||
track,
|
|
||||||
settings,
|
|
||||||
imgserver,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def create_api():
|
def create_api():
|
||||||
@ -27,14 +18,14 @@ def create_api():
|
|||||||
|
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
|
|
||||||
app.register_blueprint(album.albumbp)
|
app.register_blueprint(album.api)
|
||||||
app.register_blueprint(artist.artistbp)
|
app.register_blueprint(artist.api)
|
||||||
app.register_blueprint(track.trackbp)
|
app.register_blueprint(track.api)
|
||||||
app.register_blueprint(search.searchbp)
|
app.register_blueprint(search.api)
|
||||||
app.register_blueprint(folder.folderbp)
|
app.register_blueprint(folder.api)
|
||||||
app.register_blueprint(playlist.playlistbp)
|
app.register_blueprint(playlist.api)
|
||||||
app.register_blueprint(favorites.favbp)
|
app.register_blueprint(favorites.api)
|
||||||
app.register_blueprint(imgserver.imgbp)
|
app.register_blueprint(imgserver.api)
|
||||||
app.register_blueprint(settings.settingsbp)
|
app.register_blueprint(settings.api)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
@ -12,15 +12,14 @@ from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
|||||||
from app.db.store import Store
|
from app.db.store import Store
|
||||||
from app.models import FavType, Track
|
from app.models import FavType, Track
|
||||||
|
|
||||||
|
|
||||||
get_album_by_id = adb.get_album_by_id
|
get_album_by_id = adb.get_album_by_id
|
||||||
get_albums_by_albumartist = adb.get_albums_by_albumartist
|
get_albums_by_albumartist = adb.get_albums_by_albumartist
|
||||||
check_is_fav = favdb.check_is_favorite
|
check_is_fav = favdb.check_is_favorite
|
||||||
|
|
||||||
albumbp = Blueprint("album", __name__, url_prefix="")
|
api = Blueprint("album", __name__, url_prefix="")
|
||||||
|
|
||||||
|
|
||||||
@albumbp.route("/album", methods=["POST"])
|
@api.route("/album", methods=["POST"])
|
||||||
def get_album():
|
def get_album():
|
||||||
"""Returns all the tracks in the given album."""
|
"""Returns all the tracks in the given album."""
|
||||||
|
|
||||||
@ -88,7 +87,7 @@ def get_album():
|
|||||||
return {"tracks": tracks, "info": album}
|
return {"tracks": tracks, "info": album}
|
||||||
|
|
||||||
|
|
||||||
@albumbp.route("/album/<albumhash>/tracks", methods=["GET"])
|
@api.route("/album/<albumhash>/tracks", methods=["GET"])
|
||||||
def get_album_tracks(albumhash: str):
|
def get_album_tracks(albumhash: str):
|
||||||
"""
|
"""
|
||||||
Returns all the tracks in the given album.
|
Returns all the tracks in the given album.
|
||||||
@ -105,7 +104,7 @@ def get_album_tracks(albumhash: str):
|
|||||||
return {"tracks": tracks}
|
return {"tracks": tracks}
|
||||||
|
|
||||||
|
|
||||||
@albumbp.route("/album/from-artist", methods=["POST"])
|
@api.route("/album/from-artist", methods=["POST"])
|
||||||
def get_artist_albums():
|
def get_artist_albums():
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
|
|
||||||
|
@ -5,12 +5,12 @@ from collections import deque
|
|||||||
|
|
||||||
from flask import Blueprint, request
|
from flask import Blueprint, request
|
||||||
|
|
||||||
|
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
||||||
from app.db.store import Store
|
from app.db.store import Store
|
||||||
from app.models import Album, FavType, Track
|
from app.models import Album, FavType, Track
|
||||||
from app.utils import remove_duplicates
|
from app.utils import remove_duplicates
|
||||||
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
|
||||||
|
|
||||||
artistbp = Blueprint("artist", __name__, url_prefix="/")
|
api = Blueprint("artist", __name__, url_prefix="/")
|
||||||
|
|
||||||
|
|
||||||
class CacheEntry:
|
class CacheEntry:
|
||||||
@ -156,7 +156,7 @@ def add_albums_to_cache(artisthash: str):
|
|||||||
# =======================================================
|
# =======================================================
|
||||||
|
|
||||||
|
|
||||||
@artistbp.route("/artist/<artisthash>", methods=["GET"])
|
@api.route("/artist/<artisthash>", methods=["GET"])
|
||||||
def get_artist(artisthash: str):
|
def get_artist(artisthash: str):
|
||||||
"""
|
"""
|
||||||
Get artist data.
|
Get artist data.
|
||||||
@ -203,7 +203,7 @@ def get_artist(artisthash: str):
|
|||||||
return {"artist": artist, "tracks": tracks[:limit]}
|
return {"artist": artist, "tracks": tracks[:limit]}
|
||||||
|
|
||||||
|
|
||||||
@artistbp.route("/artist/<artisthash>/albums", methods=["GET"])
|
@api.route("/artist/<artisthash>/albums", methods=["GET"])
|
||||||
def get_artist_albums(artisthash: str):
|
def get_artist_albums(artisthash: str):
|
||||||
limit = request.args.get("limit")
|
limit = request.args.get("limit")
|
||||||
|
|
||||||
@ -261,7 +261,7 @@ def get_artist_albums(artisthash: str):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@artistbp.route("/artist/<artisthash>/tracks", methods=["GET"])
|
@api.route("/artist/<artisthash>/tracks", methods=["GET"])
|
||||||
def get_artist_tracks(artisthash: str):
|
def get_artist_tracks(artisthash: str):
|
||||||
"""
|
"""
|
||||||
Returns all artists by a given artist.
|
Returns all artists by a given artist.
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
from flask import Blueprint, request
|
from flask import Blueprint, request
|
||||||
|
|
||||||
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
||||||
from app.db.store import Store
|
from app.db.store import Store
|
||||||
from app.models import FavType
|
from app.models import FavType
|
||||||
from app.utils import UseBisection
|
from app.utils import UseBisection
|
||||||
|
|
||||||
favbp = Blueprint("favorite", __name__, url_prefix="/")
|
api = Blueprint("favorite", __name__, url_prefix="/")
|
||||||
|
|
||||||
|
|
||||||
def remove_none(items: list):
|
def remove_none(items: list):
|
||||||
return [i for i in items if i is not None]
|
return [i for i in items if i is not None]
|
||||||
|
|
||||||
|
|
||||||
@favbp.route("/favorite/add", methods=["POST"])
|
@api.route("/favorite/add", methods=["POST"])
|
||||||
def add_favorite():
|
def add_favorite():
|
||||||
"""
|
"""
|
||||||
Adds a favorite to the database.
|
Adds a favorite to the database.
|
||||||
@ -32,7 +33,7 @@ def add_favorite():
|
|||||||
return {"msg": "Added to favorites"}
|
return {"msg": "Added to favorites"}
|
||||||
|
|
||||||
|
|
||||||
@favbp.route("/favorite/remove", methods=["POST"])
|
@api.route("/favorite/remove", methods=["POST"])
|
||||||
def remove_favorite():
|
def remove_favorite():
|
||||||
"""
|
"""
|
||||||
Removes a favorite from the database.
|
Removes a favorite from the database.
|
||||||
@ -53,7 +54,7 @@ def remove_favorite():
|
|||||||
return {"msg": "Removed from favorites"}
|
return {"msg": "Removed from favorites"}
|
||||||
|
|
||||||
|
|
||||||
@favbp.route("/albums/favorite")
|
@api.route("/albums/favorite")
|
||||||
def get_favorite_albums():
|
def get_favorite_albums():
|
||||||
limit = request.args.get("limit")
|
limit = request.args.get("limit")
|
||||||
|
|
||||||
@ -77,7 +78,7 @@ def get_favorite_albums():
|
|||||||
return {"albums": fav_albums[:limit]}
|
return {"albums": fav_albums[:limit]}
|
||||||
|
|
||||||
|
|
||||||
@favbp.route("/tracks/favorite")
|
@api.route("/tracks/favorite")
|
||||||
def get_favorite_tracks():
|
def get_favorite_tracks():
|
||||||
limit = request.args.get("limit")
|
limit = request.args.get("limit")
|
||||||
|
|
||||||
@ -100,7 +101,7 @@ def get_favorite_tracks():
|
|||||||
return {"tracks": tracks[:limit]}
|
return {"tracks": tracks[:limit]}
|
||||||
|
|
||||||
|
|
||||||
@favbp.route("/artists/favorite")
|
@api.route("/artists/favorite")
|
||||||
def get_favorite_artists():
|
def get_favorite_artists():
|
||||||
limit = request.args.get("limit")
|
limit = request.args.get("limit")
|
||||||
|
|
||||||
@ -124,7 +125,7 @@ def get_favorite_artists():
|
|||||||
return {"artists": artists[:limit]}
|
return {"artists": artists[:limit]}
|
||||||
|
|
||||||
|
|
||||||
@favbp.route("/favorites")
|
@api.route("/favorites")
|
||||||
def get_all_favorites():
|
def get_all_favorites():
|
||||||
"""
|
"""
|
||||||
Returns all the favorites in the database.
|
Returns all the favorites in the database.
|
||||||
@ -191,7 +192,7 @@ def get_all_favorites():
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@favbp.route("/favorites/check")
|
@api.route("/favorites/check")
|
||||||
def check_favorite():
|
def check_favorite():
|
||||||
"""
|
"""
|
||||||
Checks if a favorite exists in the database.
|
Checks if a favorite exists in the database.
|
||||||
|
@ -2,16 +2,16 @@
|
|||||||
Contains all the folder routes.
|
Contains all the folder routes.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from flask import Blueprint, request
|
from flask import Blueprint, request
|
||||||
|
|
||||||
from app import settings
|
from app import settings
|
||||||
from app.lib.folderslib import GetFilesAndDirs
|
from app.lib.folderslib import GetFilesAndDirs
|
||||||
|
|
||||||
|
api = Blueprint("folder", __name__, url_prefix="/")
|
||||||
folderbp = Blueprint("folder", __name__, url_prefix="/")
|
|
||||||
|
|
||||||
|
|
||||||
@folderbp.route("/folder", methods=["POST"])
|
@api.route("/folder", methods=["POST"])
|
||||||
def get_folder_tree():
|
def get_folder_tree():
|
||||||
"""
|
"""
|
||||||
Returns a list of all the folders and tracks in the given folder.
|
Returns a list of all the folders and tracks in the given folder.
|
||||||
@ -21,10 +21,10 @@ def get_folder_tree():
|
|||||||
if data is not None:
|
if data is not None:
|
||||||
req_dir: str = data["folder"]
|
req_dir: str = data["folder"]
|
||||||
else:
|
else:
|
||||||
req_dir = settings.HOME_DIR
|
req_dir = settings.USER_HOME_DIR
|
||||||
|
|
||||||
if req_dir == "$home":
|
if req_dir == "$home":
|
||||||
req_dir = settings.HOME_DIR
|
req_dir = settings.USER_HOME_DIR
|
||||||
|
|
||||||
tracks, folders = GetFilesAndDirs(req_dir)()
|
tracks, folders = GetFilesAndDirs(req_dir)()
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ def get_folder_tree():
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@folderbp.route("/folder/dir-browser", methods=["POST"])
|
@api.route("/folder/dir-browser", methods=["POST"])
|
||||||
def list_folders():
|
def list_folders():
|
||||||
"""
|
"""
|
||||||
Returns a list of all the folders in the given folder.
|
Returns a list of all the folders in the given folder.
|
||||||
@ -44,10 +44,10 @@ def list_folders():
|
|||||||
try:
|
try:
|
||||||
req_dir: str = data["folder"]
|
req_dir: str = data["folder"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
req_dir = settings.HOME_DIR
|
req_dir = settings.USER_HOME_DIR
|
||||||
|
|
||||||
if req_dir == "$home":
|
if req_dir == "$home":
|
||||||
req_dir = settings.HOME_DIR
|
req_dir = settings.USER_HOME_DIR
|
||||||
|
|
||||||
entries = os.scandir(req_dir)
|
entries = os.scandir(req_dir)
|
||||||
|
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import os
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from flask import Blueprint, send_from_directory
|
from flask import Blueprint, send_from_directory
|
||||||
|
|
||||||
imgbp = Blueprint("imgserver", __name__, url_prefix="/img")
|
from app.settings import APP_DIR
|
||||||
|
|
||||||
|
api = Blueprint("imgserver", __name__, url_prefix="/img")
|
||||||
SUPPORTED_IMAGES = (".jpg", ".png", ".webp", ".jpeg")
|
SUPPORTED_IMAGES = (".jpg", ".png", ".webp", ".jpeg")
|
||||||
|
|
||||||
HOME = os.path.expanduser("~")
|
APP_DIR = Path(APP_DIR)
|
||||||
|
|
||||||
APP_DIR = Path(HOME) / ".swing"
|
|
||||||
IMG_PATH = APP_DIR / "images"
|
IMG_PATH = APP_DIR / "images"
|
||||||
ASSETS_PATH = APP_DIR / "assets"
|
ASSETS_PATH = APP_DIR / "assets"
|
||||||
|
|
||||||
@ -23,7 +22,7 @@ ARTIST_SM_PATH = ARTIST_PATH / "small"
|
|||||||
PLAYLIST_PATH = IMG_PATH / "playlists"
|
PLAYLIST_PATH = IMG_PATH / "playlists"
|
||||||
|
|
||||||
|
|
||||||
@imgbp.route("/")
|
@api.route("/")
|
||||||
def hello():
|
def hello():
|
||||||
return "<h1>Image Server</h1>"
|
return "<h1>Image Server</h1>"
|
||||||
|
|
||||||
@ -37,7 +36,7 @@ def send_fallback_img(filename: str = "default.webp"):
|
|||||||
return send_from_directory(ASSETS_PATH, filename)
|
return send_from_directory(ASSETS_PATH, filename)
|
||||||
|
|
||||||
|
|
||||||
@imgbp.route("/t/<imgpath>")
|
@api.route("/t/<imgpath>")
|
||||||
def send_lg_thumbnail(imgpath: str):
|
def send_lg_thumbnail(imgpath: str):
|
||||||
fpath = LG_THUMB_PATH / imgpath
|
fpath = LG_THUMB_PATH / imgpath
|
||||||
|
|
||||||
@ -47,7 +46,7 @@ def send_lg_thumbnail(imgpath: str):
|
|||||||
return send_fallback_img()
|
return send_fallback_img()
|
||||||
|
|
||||||
|
|
||||||
@imgbp.route("/t/s/<imgpath>")
|
@api.route("/t/s/<imgpath>")
|
||||||
def send_sm_thumbnail(imgpath: str):
|
def send_sm_thumbnail(imgpath: str):
|
||||||
fpath = SM_THUMB_PATH / imgpath
|
fpath = SM_THUMB_PATH / imgpath
|
||||||
|
|
||||||
@ -57,7 +56,7 @@ def send_sm_thumbnail(imgpath: str):
|
|||||||
return send_fallback_img()
|
return send_fallback_img()
|
||||||
|
|
||||||
|
|
||||||
@imgbp.route("/a/<imgpath>")
|
@api.route("/a/<imgpath>")
|
||||||
def send_lg_artist_image(imgpath: str):
|
def send_lg_artist_image(imgpath: str):
|
||||||
fpath = ARTIST_LG_PATH / imgpath
|
fpath = ARTIST_LG_PATH / imgpath
|
||||||
|
|
||||||
@ -67,7 +66,7 @@ def send_lg_artist_image(imgpath: str):
|
|||||||
return send_fallback_img("artist.webp")
|
return send_fallback_img("artist.webp")
|
||||||
|
|
||||||
|
|
||||||
@imgbp.route("/a/s/<imgpath>")
|
@api.route("/a/s/<imgpath>")
|
||||||
def send_sm_artist_image(imgpath: str):
|
def send_sm_artist_image(imgpath: str):
|
||||||
fpath = ARTIST_SM_PATH / imgpath
|
fpath = ARTIST_SM_PATH / imgpath
|
||||||
|
|
||||||
@ -77,7 +76,7 @@ def send_sm_artist_image(imgpath: str):
|
|||||||
return send_fallback_img("artist.webp")
|
return send_fallback_img("artist.webp")
|
||||||
|
|
||||||
|
|
||||||
@imgbp.route("/p/<imgpath>")
|
@api.route("/p/<imgpath>")
|
||||||
def send_playlist_image(imgpath: str):
|
def send_playlist_image(imgpath: str):
|
||||||
fpath = PLAYLIST_PATH / imgpath
|
fpath = PLAYLIST_PATH / imgpath
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ from app.db.store import Store
|
|||||||
from app.lib import playlistlib
|
from app.lib import playlistlib
|
||||||
from app.utils import create_new_date, remove_duplicates
|
from app.utils import create_new_date, remove_duplicates
|
||||||
|
|
||||||
playlistbp = Blueprint("playlist", __name__, url_prefix="/")
|
api = Blueprint("playlist", __name__, url_prefix="/")
|
||||||
|
|
||||||
PL = SQLitePlaylistMethods
|
PL = SQLitePlaylistMethods
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ delete_playlist = PL.delete_playlist
|
|||||||
# get_tracks_by_trackhashes = SQLiteTrackMethods.get_tracks_by_trackhashes
|
# get_tracks_by_trackhashes = SQLiteTrackMethods.get_tracks_by_trackhashes
|
||||||
|
|
||||||
|
|
||||||
@playlistbp.route("/playlists", methods=["GET"])
|
@api.route("/playlists", methods=["GET"])
|
||||||
def send_all_playlists():
|
def send_all_playlists():
|
||||||
"""
|
"""
|
||||||
Gets all the playlists.
|
Gets all the playlists.
|
||||||
@ -46,7 +46,7 @@ def send_all_playlists():
|
|||||||
return {"data": playlists}
|
return {"data": playlists}
|
||||||
|
|
||||||
|
|
||||||
@playlistbp.route("/playlist/new", methods=["POST"])
|
@api.route("/playlist/new", methods=["POST"])
|
||||||
def create_playlist():
|
def create_playlist():
|
||||||
"""
|
"""
|
||||||
Creates a new playlist. Accepts POST method with a JSON body.
|
Creates a new playlist. Accepts POST method with a JSON body.
|
||||||
@ -79,7 +79,7 @@ def create_playlist():
|
|||||||
return {"playlist": playlist}, 201
|
return {"playlist": playlist}, 201
|
||||||
|
|
||||||
|
|
||||||
@playlistbp.route("/playlist/<playlist_id>/add", methods=["POST"])
|
@api.route("/playlist/<playlist_id>/add", methods=["POST"])
|
||||||
def add_track_to_playlist(playlist_id: str):
|
def add_track_to_playlist(playlist_id: str):
|
||||||
"""
|
"""
|
||||||
Takes a playlist ID and a track hash, and adds the track to the playlist
|
Takes a playlist ID and a track hash, and adds the track to the playlist
|
||||||
@ -102,7 +102,7 @@ def add_track_to_playlist(playlist_id: str):
|
|||||||
return {"msg": "Done"}, 200
|
return {"msg": "Done"}, 200
|
||||||
|
|
||||||
|
|
||||||
@playlistbp.route("/playlist/<playlistid>")
|
@api.route("/playlist/<playlistid>")
|
||||||
def get_playlist(playlistid: str):
|
def get_playlist(playlistid: str):
|
||||||
"""
|
"""
|
||||||
Gets a playlist by id, and if it exists, it gets all the tracks in the playlist and returns them.
|
Gets a playlist by id, and if it exists, it gets all the tracks in the playlist and returns them.
|
||||||
@ -123,7 +123,7 @@ def get_playlist(playlistid: str):
|
|||||||
return {"info": playlist, "tracks": tracks}
|
return {"info": playlist, "tracks": tracks}
|
||||||
|
|
||||||
|
|
||||||
@playlistbp.route("/playlist/<playlistid>/update", methods=["PUT"])
|
@api.route("/playlist/<playlistid>/update", methods=["PUT"])
|
||||||
def update_playlist_info(playlistid: str):
|
def update_playlist_info(playlistid: str):
|
||||||
if playlistid is None:
|
if playlistid is None:
|
||||||
return {"error": "Playlist ID not provided"}, 400
|
return {"error": "Playlist ID not provided"}, 400
|
||||||
@ -188,7 +188,7 @@ def update_playlist_info(playlistid: str):
|
|||||||
# return {"data": artists}
|
# return {"data": artists}
|
||||||
|
|
||||||
|
|
||||||
@playlistbp.route("/playlist/delete", methods=["POST"])
|
@api.route("/playlist/delete", methods=["POST"])
|
||||||
def remove_playlist():
|
def remove_playlist():
|
||||||
"""
|
"""
|
||||||
Deletes a playlist by ID.
|
Deletes a playlist by ID.
|
||||||
@ -209,7 +209,7 @@ def remove_playlist():
|
|||||||
return {"msg": "Done"}, 200
|
return {"msg": "Done"}, 200
|
||||||
|
|
||||||
|
|
||||||
@playlistbp.route("/playlist/<pid>/set-image-pos", methods=["POST"])
|
@api.route("/playlist/<pid>/set-image-pos", methods=["POST"])
|
||||||
def update_image_position(pid: int):
|
def update_image_position(pid: int):
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
message = {"msg": "No data provided"}
|
message = {"msg": "No data provided"}
|
||||||
|
@ -8,7 +8,7 @@ from app import models, utils
|
|||||||
from app.db.store import Store
|
from app.db.store import Store
|
||||||
from app.lib import searchlib
|
from app.lib import searchlib
|
||||||
|
|
||||||
searchbp = Blueprint("search", __name__, url_prefix="/")
|
api = Blueprint("search", __name__, url_prefix="/")
|
||||||
|
|
||||||
|
|
||||||
SEARCH_COUNT = 12
|
SEARCH_COUNT = 12
|
||||||
@ -95,7 +95,7 @@ class DoSearch:
|
|||||||
# self.search_playlists()
|
# self.search_playlists()
|
||||||
|
|
||||||
|
|
||||||
@searchbp.route("/search/tracks", methods=["GET"])
|
@api.route("/search/tracks", methods=["GET"])
|
||||||
def search_tracks():
|
def search_tracks():
|
||||||
"""
|
"""
|
||||||
Searches for tracks that match the search query.
|
Searches for tracks that match the search query.
|
||||||
@ -113,7 +113,7 @@ def search_tracks():
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@searchbp.route("/search/albums", methods=["GET"])
|
@api.route("/search/albums", methods=["GET"])
|
||||||
def search_albums():
|
def search_albums():
|
||||||
"""
|
"""
|
||||||
Searches for albums.
|
Searches for albums.
|
||||||
@ -131,7 +131,7 @@ def search_albums():
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@searchbp.route("/search/artists", methods=["GET"])
|
@api.route("/search/artists", methods=["GET"])
|
||||||
def search_artists():
|
def search_artists():
|
||||||
"""
|
"""
|
||||||
Searches for artists.
|
Searches for artists.
|
||||||
@ -167,7 +167,7 @@ def search_artists():
|
|||||||
# }
|
# }
|
||||||
|
|
||||||
|
|
||||||
@searchbp.route("/search/top", methods=["GET"])
|
@api.route("/search/top", methods=["GET"])
|
||||||
def get_top_results():
|
def get_top_results():
|
||||||
"""
|
"""
|
||||||
Returns the top results for the search query.
|
Returns the top results for the search query.
|
||||||
@ -188,7 +188,7 @@ def get_top_results():
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@searchbp.route("/search/loadmore")
|
@api.route("/search/loadmore")
|
||||||
def search_load_more():
|
def search_load_more():
|
||||||
"""
|
"""
|
||||||
Returns more songs, albums or artists from a search query.
|
Returns more songs, albums or artists from a search query.
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
from flask import Blueprint, request
|
from flask import Blueprint, request
|
||||||
|
|
||||||
from app.db.sqlite.settings import SettingsSQLMethods as sdb
|
from app.db.sqlite.settings import SettingsSQLMethods as sdb
|
||||||
|
|
||||||
settingsbp = Blueprint("settings", __name__, url_prefix="/")
|
api = Blueprint("settings", __name__, url_prefix="/")
|
||||||
|
|
||||||
|
|
||||||
@settingsbp.route("/settings/add-root-dirs", methods=["POST"])
|
def get_child_dirs(parent: str, children: list[str]):
|
||||||
|
"""Returns child directories in a list, given a parent directory"""
|
||||||
|
|
||||||
|
return [dir for dir in children if dir.startswith(parent)]
|
||||||
|
|
||||||
|
|
||||||
|
@api.route("/settings/add-root-dirs", methods=["POST"])
|
||||||
def add_root_dirs():
|
def add_root_dirs():
|
||||||
"""
|
"""
|
||||||
Add custom root directories to the database.
|
Add custom root directories to the database.
|
||||||
@ -17,18 +24,26 @@ def add_root_dirs():
|
|||||||
return msg, 400
|
return msg, 400
|
||||||
|
|
||||||
try:
|
try:
|
||||||
new_dirs = data["new_dirs"]
|
new_dirs: list[str] = data["new_dirs"]
|
||||||
removed_dirs = data["removed"]
|
removed_dirs: list[str] = data["removed"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return msg, 400
|
return msg, 400
|
||||||
|
|
||||||
|
# --- Unregister child directories ---
|
||||||
|
db_dirs = sdb.get_root_dirs()
|
||||||
|
|
||||||
|
for _dir in new_dirs:
|
||||||
|
children = get_child_dirs(_dir, db_dirs)
|
||||||
|
removed_dirs.extend(children)
|
||||||
|
# ------------------------------------
|
||||||
|
|
||||||
sdb.add_root_dirs(new_dirs)
|
sdb.add_root_dirs(new_dirs)
|
||||||
sdb.remove_root_dirs(removed_dirs)
|
sdb.remove_root_dirs(removed_dirs)
|
||||||
|
|
||||||
return {"msg": "Added root directories to the database."}
|
return {"msg": "Updated!"}
|
||||||
|
|
||||||
|
|
||||||
@settingsbp.route("/settings/get-root-dirs", methods=["GET"])
|
@api.route("/settings/get-root-dirs", methods=["GET"])
|
||||||
def get_root_dirs():
|
def get_root_dirs():
|
||||||
"""
|
"""
|
||||||
Get custom root directories from the database.
|
Get custom root directories from the database.
|
||||||
@ -39,7 +54,7 @@ def get_root_dirs():
|
|||||||
|
|
||||||
|
|
||||||
# CURRENTLY UNUSED ROUTE 👇
|
# CURRENTLY UNUSED ROUTE 👇
|
||||||
@settingsbp.route("/settings/remove-root-dirs", methods=["POST"])
|
@api.route("/settings/remove-root-dirs", methods=["POST"])
|
||||||
def remove_root_dirs():
|
def remove_root_dirs():
|
||||||
"""
|
"""
|
||||||
Remove custom root directories from the database.
|
Remove custom root directories from the database.
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
Contains all the track routes.
|
Contains all the track routes.
|
||||||
"""
|
"""
|
||||||
from flask import Blueprint, send_file
|
from flask import Blueprint, send_file
|
||||||
|
|
||||||
from app.db.store import Store
|
from app.db.store import Store
|
||||||
|
|
||||||
trackbp = Blueprint("track", __name__, url_prefix="/")
|
api = Blueprint("track", __name__, url_prefix="/")
|
||||||
|
|
||||||
|
|
||||||
@trackbp.route("/file/<trackhash>")
|
@api.route("/file/<trackhash>")
|
||||||
def send_track_file(trackhash: str):
|
def send_track_file(trackhash: str):
|
||||||
"""
|
"""
|
||||||
Returns an audio file that matches the passed id to the client.
|
Returns an audio file that matches the passed id to the client.
|
||||||
|
@ -69,13 +69,12 @@ class ProcessArtistColors:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
db_colors: list[tuple] = list(adb.get_all_artists())
|
||||||
|
db_artisthashes = "-".join([artist[1] for artist in db_colors])
|
||||||
all_artists = Store.artists
|
all_artists = Store.artists
|
||||||
|
|
||||||
if all_artists is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
for artist in tqdm(all_artists, desc="Processing artist colors"):
|
for artist in tqdm(all_artists, desc="Processing artist colors"):
|
||||||
if len(artist.colors) == 0:
|
if artist.artisthash not in db_artisthashes:
|
||||||
self.process_color(artist)
|
self.process_color(artist)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -90,5 +89,3 @@ class ProcessArtistColors:
|
|||||||
if len(colors) > 0:
|
if len(colors) > 0:
|
||||||
adb.insert_one_artist(artisthash=artist.artisthash, colors=colors)
|
adb.insert_one_artist(artisthash=artist.artisthash, colors=colors)
|
||||||
Store.map_artist_color((0, artist.artisthash, json.dumps(colors)))
|
Store.map_artist_color((0, artist.artisthash, json.dumps(colors)))
|
||||||
|
|
||||||
# TODO: Load album and artist colors into the store.
|
|
||||||
|
3
app/migrations/__init__.py
Normal file
3
app/migrations/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Migrations module
|
||||||
|
"""
|
@ -1,16 +1,42 @@
|
|||||||
"""
|
"""
|
||||||
Contains default configs
|
Contains default configs
|
||||||
"""
|
"""
|
||||||
import multiprocessing
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
# ------- HELPER METHODS --------
|
||||||
|
def get_xdg_config_dir():
|
||||||
|
"""
|
||||||
|
Returns the XDG_CONFIG_HOME environment variable if it exists, otherwise
|
||||||
|
returns the default config directory. If none of those exist, returns the
|
||||||
|
user's home directory.
|
||||||
|
"""
|
||||||
|
xdg_config_home = os.environ.get("XDG_CONFIG_HOME")
|
||||||
|
|
||||||
|
if xdg_config_home:
|
||||||
|
return xdg_config_home
|
||||||
|
|
||||||
|
try:
|
||||||
|
alt_dir = os.path.join(os.environ.get("HOME"), ".config")
|
||||||
|
|
||||||
|
if os.path.exists(alt_dir):
|
||||||
|
return alt_dir
|
||||||
|
except TypeError:
|
||||||
|
return os.path.expanduser("~")
|
||||||
|
|
||||||
|
|
||||||
|
# ------- HELPER METHODS --------
|
||||||
|
|
||||||
|
|
||||||
APP_VERSION = "Swing v.1.0.0.beta.1"
|
APP_VERSION = "Swing v.1.0.0.beta.1"
|
||||||
|
|
||||||
# paths
|
# paths
|
||||||
CONFIG_FOLDER = ".swing"
|
XDG_CONFIG_DIR = get_xdg_config_dir()
|
||||||
HOME_DIR = os.path.expanduser("~")
|
USER_HOME_DIR = os.path.expanduser("~")
|
||||||
|
|
||||||
APP_DIR = os.path.join(HOME_DIR, CONFIG_FOLDER)
|
CONFIG_FOLDER = "swing" if XDG_CONFIG_DIR != USER_HOME_DIR else ".swing"
|
||||||
|
|
||||||
|
APP_DIR = os.path.join(XDG_CONFIG_DIR, CONFIG_FOLDER)
|
||||||
IMG_PATH = os.path.join(APP_DIR, "images")
|
IMG_PATH = os.path.join(APP_DIR, "images")
|
||||||
|
|
||||||
ARTIST_IMG_PATH = os.path.join(IMG_PATH, "artists")
|
ARTIST_IMG_PATH = os.path.join(IMG_PATH, "artists")
|
||||||
@ -37,8 +63,6 @@ DEFAULT_ARTIST_IMG = IMG_ARTIST_URI + "0.webp"
|
|||||||
|
|
||||||
LAST_FM_API_KEY = "762db7a44a9e6fb5585661f5f2bdf23a"
|
LAST_FM_API_KEY = "762db7a44a9e6fb5585661f5f2bdf23a"
|
||||||
|
|
||||||
CPU_COUNT = multiprocessing.cpu_count()
|
|
||||||
|
|
||||||
THUMB_SIZE = 400
|
THUMB_SIZE = 400
|
||||||
SM_THUMB_SIZE = 64
|
SM_THUMB_SIZE = 64
|
||||||
SM_ARTIST_IMG_SIZE = 64
|
SM_ARTIST_IMG_SIZE = 64
|
||||||
@ -46,24 +70,9 @@ SM_ARTIST_IMG_SIZE = 64
|
|||||||
The size of extracted images in pixels
|
The size of extracted images in pixels
|
||||||
"""
|
"""
|
||||||
|
|
||||||
LOGGER_ENABLE: bool = True
|
|
||||||
|
|
||||||
FILES = ["flac", "mp3", "wav", "m4a"]
|
FILES = ["flac", "mp3", "wav", "m4a"]
|
||||||
SUPPORTED_FILES = tuple(f".{file}" for file in FILES)
|
SUPPORTED_FILES = tuple(f".{file}" for file in FILES)
|
||||||
|
|
||||||
SUPPORTED_IMAGES = (".jpg", ".png", ".webp", ".jpeg")
|
|
||||||
|
|
||||||
SUPPORTED_DIR_IMAGES = [
|
|
||||||
"folder",
|
|
||||||
"cover",
|
|
||||||
"album",
|
|
||||||
"front",
|
|
||||||
]
|
|
||||||
|
|
||||||
# ===== DB =========
|
|
||||||
USE_MONGO = False
|
|
||||||
|
|
||||||
|
|
||||||
# ===== SQLite =====
|
# ===== SQLite =====
|
||||||
APP_DB_NAME = "swing.db"
|
APP_DB_NAME = "swing.db"
|
||||||
USER_DATA_DB_NAME = "userdata.db"
|
USER_DATA_DB_NAME = "userdata.db"
|
||||||
|
@ -4,7 +4,6 @@ Contains the functions to prepare the server for use.
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
import caribou # pylint: disable=import-error
|
|
||||||
|
|
||||||
from app import settings
|
from app import settings
|
||||||
from app.db.sqlite import create_connection, create_tables, queries
|
from app.db.sqlite import create_connection, create_tables, queries
|
||||||
@ -64,10 +63,6 @@ def create_config_dir() -> None:
|
|||||||
"""
|
"""
|
||||||
Creates the config directory if it doesn't exist.
|
Creates the config directory if it doesn't exist.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
home_dir = os.path.expanduser("~")
|
|
||||||
config_folder = os.path.join(home_dir, settings.CONFIG_FOLDER)
|
|
||||||
|
|
||||||
thumb_path = os.path.join("images", "thumbnails")
|
thumb_path = os.path.join("images", "thumbnails")
|
||||||
small_thumb_path = os.path.join(thumb_path, "small")
|
small_thumb_path = os.path.join(thumb_path, "small")
|
||||||
large_thumb_path = os.path.join(thumb_path, "large")
|
large_thumb_path = os.path.join(thumb_path, "large")
|
||||||
@ -91,7 +86,7 @@ def create_config_dir() -> None:
|
|||||||
]
|
]
|
||||||
|
|
||||||
for _dir in dirs:
|
for _dir in dirs:
|
||||||
path = os.path.join(config_folder, _dir)
|
path = os.path.join(settings.APP_DIR, _dir)
|
||||||
exists = os.path.exists(path)
|
exists = os.path.exists(path)
|
||||||
|
|
||||||
if not exists:
|
if not exists:
|
||||||
@ -114,19 +109,6 @@ def setup_sqlite():
|
|||||||
create_tables(app_db_conn, queries.CREATE_APPDB_TABLES)
|
create_tables(app_db_conn, queries.CREATE_APPDB_TABLES)
|
||||||
create_tables(playlist_db_conn, queries.CREATE_USERDATA_TABLES)
|
create_tables(playlist_db_conn, queries.CREATE_USERDATA_TABLES)
|
||||||
|
|
||||||
userdb_migrations = get_home_res_path("app") / "migrations" / "userdata"
|
|
||||||
maindb_migrations = get_home_res_path("app") / "migrations" / "main"
|
|
||||||
|
|
||||||
caribou.upgrade(
|
|
||||||
APP_DB_PATH,
|
|
||||||
maindb_migrations,
|
|
||||||
)
|
|
||||||
|
|
||||||
caribou.upgrade(
|
|
||||||
str(USERDATA_DB_PATH),
|
|
||||||
str(userdb_migrations),
|
|
||||||
)
|
|
||||||
|
|
||||||
app_db_conn.close()
|
app_db_conn.close()
|
||||||
playlist_db_conn.close()
|
playlist_db_conn.close()
|
||||||
|
|
||||||
|
29
app/utils.py
29
app/utils.py
@ -5,6 +5,7 @@ from pathlib import Path
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import platform
|
||||||
import socket as Socket
|
import socket as Socket
|
||||||
import hashlib
|
import hashlib
|
||||||
import threading
|
import threading
|
||||||
@ -38,19 +39,22 @@ def run_fast_scandir(__dir: str, full=False) -> tuple[list[str], list[str]]:
|
|||||||
subfolders = []
|
subfolders = []
|
||||||
files = []
|
files = []
|
||||||
|
|
||||||
for f in os.scandir(__dir):
|
try:
|
||||||
if f.is_dir() and not f.name.startswith("."):
|
for _files in os.scandir(__dir):
|
||||||
subfolders.append(f.path)
|
if _files.is_dir() and not _files.name.startswith("."):
|
||||||
if f.is_file():
|
subfolders.append(_files.path)
|
||||||
ext = os.path.splitext(f.name)[1].lower()
|
if _files.is_file():
|
||||||
|
ext = os.path.splitext(_files.name)[1].lower()
|
||||||
if ext in SUPPORTED_FILES:
|
if ext in SUPPORTED_FILES:
|
||||||
files.append(f.path)
|
files.append(_files.path)
|
||||||
|
|
||||||
if full or len(files) == 0:
|
if full or len(files) == 0:
|
||||||
for _dir in list(subfolders):
|
for _dir in list(subfolders):
|
||||||
sf, f = run_fast_scandir(_dir, full=True)
|
sub_dirs, _files = run_fast_scandir(_dir, full=True)
|
||||||
subfolders.extend(sf)
|
subfolders.extend(sub_dirs)
|
||||||
files.extend(f)
|
files.extend(_files)
|
||||||
|
except PermissionError:
|
||||||
|
return [], []
|
||||||
|
|
||||||
return subfolders, files
|
return subfolders, files
|
||||||
|
|
||||||
@ -239,3 +243,10 @@ def get_ip():
|
|||||||
soc.close()
|
soc.close()
|
||||||
|
|
||||||
return ip_address
|
return ip_address
|
||||||
|
|
||||||
|
|
||||||
|
def is_windows():
|
||||||
|
"""
|
||||||
|
Returns True if the OS is Windows.
|
||||||
|
"""
|
||||||
|
return platform.system() == "Windows"
|
||||||
|
11
manage.py
11
manage.py
@ -13,7 +13,7 @@ from app.functions import run_periodic_checks
|
|||||||
from app.lib.watchdogg import Watcher as WatchDog
|
from app.lib.watchdogg import Watcher as WatchDog
|
||||||
from app.settings import APP_VERSION, HELP_MESSAGE, TCOLOR
|
from app.settings import APP_VERSION, HELP_MESSAGE, TCOLOR
|
||||||
from app.setup import run_setup
|
from app.setup import run_setup
|
||||||
from app.utils import background, get_home_res_path, get_ip
|
from app.utils import background, get_home_res_path, get_ip, is_windows
|
||||||
|
|
||||||
werkzeug = logging.getLogger("werkzeug")
|
werkzeug = logging.getLogger("werkzeug")
|
||||||
werkzeug.setLevel(logging.ERROR)
|
werkzeug.setLevel(logging.ERROR)
|
||||||
@ -80,6 +80,8 @@ class HandleArgs:
|
|||||||
config["DEFAULT"]["BUILD"] = "True"
|
config["DEFAULT"]["BUILD"] = "True"
|
||||||
config.write(file)
|
config.write(file)
|
||||||
|
|
||||||
|
_s = ";" if is_windows() else ":"
|
||||||
|
|
||||||
bundler.run(
|
bundler.run(
|
||||||
[
|
[
|
||||||
"manage.py",
|
"manage.py",
|
||||||
@ -87,9 +89,10 @@ class HandleArgs:
|
|||||||
"--name",
|
"--name",
|
||||||
"swingmusic",
|
"swingmusic",
|
||||||
"--clean",
|
"--clean",
|
||||||
"--add-data=assets:assets",
|
f"--add-data=assets{_s}assets",
|
||||||
"--add-data=client:client",
|
f"--add-data=client{_s}client",
|
||||||
"--add-data=pyinstaller.config.ini:.",
|
f"--add-data=app/migrations{_s}app/migrations",
|
||||||
|
f"--add-data=pyinstaller.config.ini{_s}.",
|
||||||
"-y",
|
"-y",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
46
poetry.lock
generated
46
poetry.lock
generated
@ -12,23 +12,11 @@ files = [
|
|||||||
{file = "altgraph-0.17.3.tar.gz", hash = "sha256:ad33358114df7c9416cdb8fa1eaa5852166c505118717021c6a8c7c7abbd03dd"},
|
{file = "altgraph-0.17.3.tar.gz", hash = "sha256:ad33358114df7c9416cdb8fa1eaa5852166c505118717021c6a8c7c7abbd03dd"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "argparse"
|
|
||||||
version = "1.4.0"
|
|
||||||
description = "Python command-line parsing library"
|
|
||||||
category = "main"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "argparse-1.4.0-py2.py3-none-any.whl", hash = "sha256:c31647edb69fd3d465a847ea3157d37bed1f95f19760b11a47aa91c04b666314"},
|
|
||||||
{file = "argparse-1.4.0.tar.gz", hash = "sha256:62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "astroid"
|
name = "astroid"
|
||||||
version = "2.12.12"
|
version = "2.12.12"
|
||||||
description = "An abstract syntax tree for Python with inference support."
|
description = "An abstract syntax tree for Python with inference support."
|
||||||
category = "main"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7.2"
|
python-versions = ">=3.7.2"
|
||||||
files = [
|
files = [
|
||||||
@ -107,20 +95,6 @@ d = ["aiohttp (>=3.7.4)"]
|
|||||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||||
uvloop = ["uvloop (>=0.15.2)"]
|
uvloop = ["uvloop (>=0.15.2)"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "caribou"
|
|
||||||
version = "0.3"
|
|
||||||
description = "python migrations for sqlite databases"
|
|
||||||
category = "main"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "caribou-0.3.0.tar.gz", hash = "sha256:5ca6e6e6ad7d3175137c68d809e203fbd931f79163a5613808a789449fef7863"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
argparse = ">=1.0.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "certifi"
|
name = "certifi"
|
||||||
version = "2022.5.18.1"
|
version = "2022.5.18.1"
|
||||||
@ -194,7 +168,7 @@ pillow = ">=3.3.1"
|
|||||||
name = "dill"
|
name = "dill"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
description = "serialize all of python"
|
description = "serialize all of python"
|
||||||
category = "main"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -351,7 +325,7 @@ files = [
|
|||||||
name = "isort"
|
name = "isort"
|
||||||
version = "5.10.1"
|
version = "5.10.1"
|
||||||
description = "A Python utility / library to sort Python imports."
|
description = "A Python utility / library to sort Python imports."
|
||||||
category = "main"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6.1,<4.0"
|
python-versions = ">=3.6.1,<4.0"
|
||||||
files = [
|
files = [
|
||||||
@ -399,7 +373,7 @@ i18n = ["Babel (>=2.7)"]
|
|||||||
name = "lazy-object-proxy"
|
name = "lazy-object-proxy"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
description = "A fast and thorough lazy object proxy."
|
description = "A fast and thorough lazy object proxy."
|
||||||
category = "main"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -493,7 +467,7 @@ files = [
|
|||||||
name = "mccabe"
|
name = "mccabe"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
description = "McCabe checker, plugin for flake8"
|
description = "McCabe checker, plugin for flake8"
|
||||||
category = "main"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
files = [
|
files = [
|
||||||
@ -630,7 +604,7 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa
|
|||||||
name = "platformdirs"
|
name = "platformdirs"
|
||||||
version = "2.5.2"
|
version = "2.5.2"
|
||||||
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||||
category = "main"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
@ -720,7 +694,7 @@ files = [
|
|||||||
name = "pylint"
|
name = "pylint"
|
||||||
version = "2.15.5"
|
version = "2.15.5"
|
||||||
description = "python code static checker"
|
description = "python code static checker"
|
||||||
category = "main"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7.2"
|
python-versions = ">=3.7.2"
|
||||||
files = [
|
files = [
|
||||||
@ -988,7 +962,7 @@ files = [
|
|||||||
name = "tomlkit"
|
name = "tomlkit"
|
||||||
version = "0.11.6"
|
version = "0.11.6"
|
||||||
description = "Style preserving TOML library"
|
description = "Style preserving TOML library"
|
||||||
category = "main"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
files = [
|
files = [
|
||||||
@ -1106,7 +1080,7 @@ watchdog = ["watchdog"]
|
|||||||
name = "wrapt"
|
name = "wrapt"
|
||||||
version = "1.14.1"
|
version = "1.14.1"
|
||||||
description = "Module for decorators, wrappers and monkey patching."
|
description = "Module for decorators, wrappers and monkey patching."
|
||||||
category = "main"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||||
files = [
|
files = [
|
||||||
@ -1179,4 +1153,4 @@ files = [
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = ">=3.10,<3.12"
|
python-versions = ">=3.10,<3.12"
|
||||||
content-hash = "83ce6d95a8e6bdefff93a3badca9e7b7b53174eaea85f908e9cea9a37afaec7c"
|
content-hash = "6f6126fbaa8f114c90cef637e0bc996d63d3dc93f6ed2e90e36ef696cdd0cfc5"
|
||||||
|
@ -20,7 +20,6 @@ hypothesis = "^6.56.3"
|
|||||||
pytest = "^7.1.3"
|
pytest = "^7.1.3"
|
||||||
Unidecode = "^1.3.6"
|
Unidecode = "^1.3.6"
|
||||||
pyinstaller = "^5.7.0"
|
pyinstaller = "^5.7.0"
|
||||||
caribou = "^0.3.0"
|
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
pylint = "^2.15.5"
|
pylint = "^2.15.5"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user