Commit 118d8764 authored by Fence's avatar Fence 🌈

add covers resource and version api

parent 6fc121d9
......@@ -2,7 +2,8 @@ import sys
import jwt
from datetime import datetime, timedelta
expires = 15
expires = 100
# todo add third argument
payload = {"song": "5b9ae72fc0368e3b9c8a6027" }
key = None
......
from minor import App
app = App({"UPLOAD_DIR": "./upload"})
app = App({
"MUSIC_UPLOAD_DIR": "./upload",
"IMAGE_UPLOAD_DIR": "./upload"
})
app.run()
\ No newline at end of file
from flask import Flask
from minor.controller import ApiController, MusicController
from minor.controller import ApiController, MusicController, CoverController
from minor.error_handlers import set_error_handlers
class App(object):
......@@ -13,7 +13,9 @@ class App(object):
db.init_app(self._flask)
ApiController(self).register(self._flask)
MusicController(self._flask.config["UPLOAD_DIR"]).register(self._flask)
MusicController(self._flask.config["MUSIC_UPLOAD_DIR"],
self._flask.config["IMAGE_UPLOAD_DIR"]).register(self._flask)
CoverController(self._flask.config["IMAGE_UPLOAD_DIR"]).register(self._flask)
def run(self, host="127.0.0.1", port=5000):
self._flask.run(host=host, port=port)
......
from minor.controller.api import ApiController
from minor.controller.music import MusicController
\ No newline at end of file
from minor.controller.music import MusicController
from minor.controller.covers import CoverController
import json
import os
import uuid
from flask_controller import FlaskController, route
from werkzeug.utils import secure_filename
from minor.decorators import auth_required
from flask import request, jsonify, send_file
from minor.model import Song, Cover
from minor.util import get_ext, img_exts, get_page, transform_mongo_dict
def generate_file_name(extension):
return str(uuid.uuid1()) + "." + extension
@route("/api/v1/covers")
class CoverController(FlaskController):
def __init__(self, upload_dir):
self._upload_dir = upload_dir
@auth_required
@route("/", methods=["GET"])
def all_covers(self, payload=None):
start = request.args.get("start")
try:
if start is not None:
start = int(start)
else:
start = 0
except ValueError:
return jsonify({"code": 400, "message": "bad_request"}), 400
limit = 20
covers = get_page(Cover, start, limit)
count = Cover.objects.count()
# covers is an array of dicts which represent Cover models
# also songs is an array of arrays with objectid's... mongoengine is really bad for serialization
for cover in covers:
print(cover)
cover["songs"] = list(map(lambda s: s[0]["$oid"], cover["songs"]))
if covers:
return jsonify({"code": 200, "message": "ok", "data": covers, "count": count, "limit": limit}), 200
else:
return jsonify({"code": 204, "message": "no content", "count": 0, "limit": limit}), 204
@auth_required
@route("/<id>", methods=["GET"])
def cover_by_id(self, id, payload=None):
try:
cover = Cover.objects.get(id=id)
except Cover.DoesNotExist:
return jsonify({"code": 404, "message": "not found"}), 404
cover = transform_mongo_dict(json.loads(cover.to_json()))
# songs is an array of arrays with objectid's...
# mongoengine is really bad for serialization
cover["songs"] = list(map(lambda s: s[0]["$oid"], cover["songs"]))
return jsonify({"code": 200, "message": "ok", "data": cover}), 200
@auth_required
@route("/<id>/file", methods=["GET"])
def cover_file(self, id, payload=None):
try:
cover = Cover.objects.get(id=id)
except Cover.DoesNotExist:
return jsonify({"code": 404, "message": "not found"}), 404
return send_file(os.path.abspath(os.path.join(self._upload_dir, secure_filename(cover.file))))
@auth_required
@route("/", methods=["POST"])
def cover_upload(self, payload=None):
if 'file' in request.files:
file = request.files["file"]
if file.filename is not '':
ext = get_ext(file.filename, img_exts)
if ext is not None:
name = secure_filename(generate_file_name(ext))
path = os.path.join(self._upload_dir, name)
file.save(path)
# add new cover to db
cover = Cover(file=name, songs=[])
cover.save()
cover.reload()
return jsonify({"code": 200, "message": "ok", "data": {"id": str(cover.id)}}), 200
return jsonify({"code": 400, "message": "bad_request"}), 400
@auth_required
@route("/<id>/song", methods=["POST"])
def cover_add_song(self, id, payload=None):
json = request.get_json()
try:
cover = Cover.objects.get(id=id)
except Cover.DoesNotExist:
return jsonify({"code": 404, "message": "not found"}), 404
if "song_id" in json:
try:
song = Song.objects.get(id=json["song_id"])
except Song.DoesNotExist:
return jsonify({"code": 400, "message": "song does not exist"}), 400
cover.update(push__songs=[song])
return jsonify({"code": 200, "message": "ok"}), 200
else:
return jsonify({"code": 400, "message": "bad_request"}), 400
import os
import os.path
import json
from flask import request, jsonify, Response
from flask import request, jsonify, Response, send_file
from flask_controller import FlaskController, route
from werkzeug.utils import secure_filename
from mutagen.mp3 import MP3
from minor.decorators import json_required, auth_required
from minor.model import Song
from minor.util import get_ext, transform_mongo_dict
from minor.model import Song, Cover
from minor.util import get_ext, transform_mongo_dict, get_page
@route("/api/music")
@route("/api/v1/music")
class MusicController(FlaskController):
def __init__(self, upload_dir):
def __init__(self, upload_dir, cover_dir):
self._upload_dir = upload_dir
self._cover_upload_dir = cover_dir
@auth_required
@route("/listen")
......@@ -37,25 +38,25 @@ class MusicController(FlaskController):
@route("/songs")
def all_songs(self, payload=None):
start = request.args.get("start")
limit = 20
if start is None:
start = 0
else:
start = int(start) - 1
try:
if start is not None:
start = int(start)
else:
start = 0
except ValueError:
return jsonify({"code": 400, "message": "bad_request"}), 400
songs = Song.objects.skip(start).limit(limit)
count = Song.objects.count()
limit = 20
# ech mongoengine is garbage
songs_dict_arr = json.loads(songs.to_json())
songs = list(map(lambda x: transform_mongo_dict(x), songs_dict_arr))
songs = get_page(Song, start, limit)
count = Song.objects.count()
# check if songs is empty
if songs:
return jsonify({"code": 200, "message": "ok", "data": songs, "count": count, "limit": limit}), 200
else:
return jsonify({"code": 400, "message": "bad_request"}), 400
return jsonify({"code": 204, "message": "no content", "count": 0, "limit": limit}), 204
@auth_required
@route("/songs/<id>")
......@@ -82,6 +83,19 @@ class MusicController(FlaskController):
else:
return jsonify({"code": 200, "message": "ok", "data": False}), 200
@auth_required
@route("/songs/<id>/cover")
def song_cover(self, id, payload=None):
try:
song = Song.objects.get(id=id)
except Song.DoesNotExist:
return jsonify({"code": 404, "message": "not found"}), 404
try:
cover = Cover.objects(songs=[song]).limit(1).get()
return send_file(os.path.abspath(os.path.join(self._cover_upload_dir, secure_filename(cover.file))))
except Cover.DoesNotExist:
return jsonify({"code": 204, "message": "no content"}), 204
@auth_required
@json_required
@route("/songs", methods=["POST"])
......
......@@ -15,6 +15,11 @@ class Song(Document):
playtime = IntField()
class Cover(Document):
file = StringField(required=True)
songs = ListField(ReferenceField(Song, reverse_delete_rule=CASCADE))
class MajorInstance(Document):
issuer = StringField(required=True)
key = StringField(required=True)
exts = ["mp3", "ogg", "flac"]
import json
img_exts = ["jpg", "jpeg", "png"]
song_exts = ["mp3", "ogg", "flac"]
def get_ext(filename):
def get_ext(filename, exts=song_exts):
if '.' in filename and filename.rsplit('.', 1)[1].lower() in exts:
return filename.rsplit('.', 1)[1].lower()
else:
......@@ -12,3 +15,15 @@ def transform_mongo_dict(mongo_dict):
mongo_dict["id"] = mongo_dict["_id"]["$oid"]
del mongo_dict["_id"]
return mongo_dict
def get_page(model, start=0, limit=20):
if start != 0:
# can't really remember why we do this uhhhh
start = start - 1
models = model.objects.skip(start).limit(limit)
# ech mongoengine is garbage
dict_arr = json.loads(models.to_json())
return list(map(lambda x: transform_mongo_dict(x), dict_arr))
number = 0.1
number = 0.5
name = "minor"
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment