Rework the backend api
This commit is contained in:
parent
fea3a714f0
commit
0e71eab1ee
@ -2,10 +2,12 @@ import json
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import falcon
|
import falcon
|
||||||
|
import mongoengine
|
||||||
|
|
||||||
from .tools import JsonRequest, JsonResponse, error_handler
|
from .tools import JsonRequest, JsonResponse, error_handler
|
||||||
from .controllers import *
|
from .controllers import *
|
||||||
|
|
||||||
|
|
||||||
class AboutResource():
|
class AboutResource():
|
||||||
|
|
||||||
def on_get(self, req, resp):
|
def on_get(self, req, resp):
|
||||||
@ -35,15 +37,19 @@ class AboutResource():
|
|||||||
|
|
||||||
resp.body = json.dumps(r, indent=4)
|
resp.body = json.dumps(r, indent=4)
|
||||||
|
|
||||||
|
mongoengine.connect('KaruMedia', connect=False)
|
||||||
|
|
||||||
app = application = falcon.API(request_type=JsonRequest, response_type=JsonResponse)
|
app = application = falcon.API(request_type=JsonRequest, response_type=JsonResponse)
|
||||||
app.add_error_handler(ValueError, error_handler)
|
app.add_error_handler(ValueError, error_handler)
|
||||||
|
app.add_error_handler(mongoengine.DoesNotExist, error_handler)
|
||||||
app.add_route("/", AboutResource())
|
app.add_route("/", AboutResource())
|
||||||
|
|
||||||
path = Path("/home/arti/Videod")
|
path = Path("/srv/media/")
|
||||||
|
|
||||||
app.add_route("/movies", MoviesCollection(path))
|
app.add_route("/movies", MoviesCollection(path))
|
||||||
app.add_route("/movies/{movie}", MoviesResource(path))
|
app.add_route("/movies/{movie}", MoviesResource(path))
|
||||||
app.add_route("/movies/{movie}/stream", MovieStreamUrlResource(path))
|
|
||||||
|
|
||||||
app.add_route("/magnet", MagnetResource())
|
app.add_route("/magnet", MagnetResource())
|
||||||
|
|
||||||
|
app.add_route("/tasks", TaskCollection())
|
||||||
|
app.add_route("/tasks/{task_id}", TaskResource())
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import json
|
import json
|
||||||
|
from . import tasks
|
||||||
from falcon import HTTPInternalServerError, HTTP_201
|
from falcon import HTTPInternalServerError, HTTP_201
|
||||||
|
from bson.objectid import ObjectId
|
||||||
from .tools import TODOException
|
from .tools import TODOException
|
||||||
|
from .models import *
|
||||||
|
from pprint import pprint
|
||||||
|
from urllib.parse import quote
|
||||||
|
|
||||||
|
|
||||||
movie_name_and_year = re.compile("(.*)\((.*)\)")
|
movie_name_and_year = re.compile("(.*)\((.*)\)")
|
||||||
|
|
||||||
@ -10,55 +16,52 @@ class BaseMovieResource():
|
|||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
self.path = path
|
self.path = path
|
||||||
|
|
||||||
|
def build_movie_object(media):
|
||||||
|
mobj = {
|
||||||
|
"title":media.title,
|
||||||
|
"title_english":media.title,
|
||||||
|
"title_long": f"{media.title} ({media.year})",
|
||||||
|
"year":media.year,
|
||||||
|
"imdb_code": media.imdb_id,
|
||||||
|
"rating": media.rating,
|
||||||
|
"summary": media.plot_outline,
|
||||||
|
"synopsis": media.plot_outline,
|
||||||
|
"mpa_rating": media.mpa_rating,
|
||||||
|
"genres": media.genres,
|
||||||
|
"yt_trailer_code": media.yt_trailer_code,
|
||||||
|
"state": "ok",
|
||||||
|
"id": media.id
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
mobj["runtime"] = media.runtime // 100
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if media.plots:
|
||||||
|
mobj["description_full"] = media.plots[0]
|
||||||
|
|
||||||
|
relevant_tasks = list(Task.objects(imdb_id=media.imdb_id, state__ne="done"))
|
||||||
|
if relevant_tasks:
|
||||||
|
pprint(relevant_tasks)
|
||||||
|
mobj["state"] = "tasks_running"
|
||||||
|
mobj["relevant_tasks"] = [task.id for task in relevant_tasks]
|
||||||
|
|
||||||
|
mobj["streams"] = {}
|
||||||
|
stream_urls = list(MediaFile.objects(media=media))
|
||||||
|
if stream_urls:
|
||||||
|
mobj["streams"] = {media_file.resolution: media_file.url for media_file in stream_urls if media_file.mimetype.startswith("video")}
|
||||||
|
|
||||||
|
mobj["small_cover_image"] = f"https://media.arti.ee/Filmid/{quote(mobj['title_long'])}/cover.jpg"
|
||||||
|
mobj["medium_cover_image"] = mobj["small_cover_image"]
|
||||||
|
mobj["large_cover_image"] = mobj["medium_cover_image"]
|
||||||
|
|
||||||
|
return mobj
|
||||||
|
|
||||||
class MoviesCollection(BaseMovieResource):
|
class MoviesCollection(BaseMovieResource):
|
||||||
|
|
||||||
def on_get(self, req, resp):
|
def on_get(self, req, resp):
|
||||||
movie_paths = [p for p in (self.path / 'Filmid').iterdir() if p.is_dir()]
|
|
||||||
movies = []
|
movies = []
|
||||||
for movie_path in movie_paths:
|
for media in Media.objects:
|
||||||
if not (movie_path / "metadata.json").exists():
|
movies.append(build_movie_object(media))
|
||||||
match = movie_name_and_year.match(movie_path.name)
|
|
||||||
if not match:
|
|
||||||
mobj = {
|
|
||||||
"title":movie_path.name,
|
|
||||||
"title_english":movie_path.name,
|
|
||||||
"title_long":movie_path.name,
|
|
||||||
"state":"ok"
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
movie_name, movie_year = match.groups()
|
|
||||||
mobj = {
|
|
||||||
"title":movie_name,
|
|
||||||
"title_english":movie_name,
|
|
||||||
"title_long":movie_path.name,
|
|
||||||
"year":movie_year,
|
|
||||||
"state": "ok"
|
|
||||||
}
|
|
||||||
movies.append(mobj)
|
|
||||||
continue
|
|
||||||
with (movie_path / "metadata.json").open() as f:
|
|
||||||
metadata = json.loads(f.read())
|
|
||||||
mobj = {
|
|
||||||
"title":metadata["title"],
|
|
||||||
"title_english":metadata["title"],
|
|
||||||
"title_long":movie_path.name,
|
|
||||||
"year":metadata["year"],
|
|
||||||
"imdb_code": metadata["imdb_id"],
|
|
||||||
"rating": metadata["rating"],
|
|
||||||
"summary": metadata["plot_outline"],
|
|
||||||
"synopsis": metadata["plot_outline"],
|
|
||||||
"mpa_rating": metadata["certification"],
|
|
||||||
"genres": metadata["genres"],
|
|
||||||
"yt_trailer_code": metadata["yt_trailer_code"],
|
|
||||||
"state": "ok"
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
metadata["runtime"] = int(metadata["runtime"]) // 100
|
|
||||||
except ValueError as err:
|
|
||||||
pass
|
|
||||||
if metadata["plots"]:
|
|
||||||
mobj["description_full"] = metadata["plots"][0]
|
|
||||||
movies.append(mobj)
|
|
||||||
jobj = {"data":{
|
jobj = {"data":{
|
||||||
"limit":len(movies),
|
"limit":len(movies),
|
||||||
"count":len(movies),
|
"count":len(movies),
|
||||||
@ -73,23 +76,37 @@ class MoviesCollection(BaseMovieResource):
|
|||||||
class MoviesResource(BaseMovieResource):
|
class MoviesResource(BaseMovieResource):
|
||||||
|
|
||||||
def on_get(self, req, resp, movie):
|
def on_get(self, req, resp, movie):
|
||||||
resp.json = [{"path": self.path, "movie":movie}]
|
try:
|
||||||
|
media = Media.objects.get(id=movie)
|
||||||
class MovieStreamUrlResource(BaseMovieResource):
|
except ValidationError:
|
||||||
|
media = Media.objects.get(imdb_id=movie)
|
||||||
def on_get(self, req, resp, movie):
|
resp.json = build_movie_object(media)
|
||||||
movie_name = movie
|
|
||||||
path = self.path / "Filmid"
|
|
||||||
movie_files = os.listdir(str(path / movie_name))
|
|
||||||
sizes = []
|
|
||||||
for movie_file in movie_files:
|
|
||||||
sizes.append((os.path.getsize(str(path / movie_name / movie_file)), movie_file))
|
|
||||||
file_name = sorted(sizes)[-1][1]
|
|
||||||
resp.json = {
|
|
||||||
"default": 'https://media.arti.ee/Filmid/{}/{}'.format(movie_name.replace(" ", "%20"), file_name.replace(" ", "%20"))
|
|
||||||
}
|
|
||||||
|
|
||||||
class MagnetResource():
|
class MagnetResource():
|
||||||
|
|
||||||
def on_post(self, req, resp):
|
def on_post(self, req, resp):
|
||||||
resp.json = [req.json]
|
json = req.json
|
||||||
|
if not 'info_hash' in json:
|
||||||
|
raise ValueError("info_hash missing from request")
|
||||||
|
task = TaskMetainfoDl(info_hash=json['info_hash'])
|
||||||
|
task.imdb_code = json.get('imdb_code')
|
||||||
|
task.save()
|
||||||
|
tasks.metainfo_dl(str(task.id))
|
||||||
|
resp.json = {"task_id":task.id}
|
||||||
|
|
||||||
|
|
||||||
|
class TaskCollection():
|
||||||
|
|
||||||
|
def on_get(self, req, resp):
|
||||||
|
tasks = list()
|
||||||
|
for task in Task.objects:
|
||||||
|
tasks.append(task.to_mongo())
|
||||||
|
resp.json = tasks
|
||||||
|
|
||||||
|
class TaskResource():
|
||||||
|
def on_get(self, req, resp, task_id):
|
||||||
|
task = Task.objects.get(id=task_id)
|
||||||
|
resp.json = task.to_mongo()
|
||||||
|
|
||||||
|
def on_delete(self, req, resp, task_id):
|
||||||
|
Task.objects(id=task_id).delete()
|
||||||
|
54
api/karumedia/models.py
Normal file
54
api/karumedia/models.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import datetime
|
||||||
|
from mongoengine import *
|
||||||
|
|
||||||
|
class Media(Document):
|
||||||
|
title = StringField()
|
||||||
|
slug = StringField(unique=True)
|
||||||
|
imdb_id = StringField(unique=True)
|
||||||
|
runtime = IntField()
|
||||||
|
genres = ListField(StringField())
|
||||||
|
mpa_rating = StringField()
|
||||||
|
rating = FloatField()
|
||||||
|
yt_trailer_code = StringField()
|
||||||
|
date_added = DateTimeField(default=datetime.datetime.now)
|
||||||
|
parrent = ReferenceField('self')
|
||||||
|
season = IntField()
|
||||||
|
episode = IntField()
|
||||||
|
release_date = StringField()
|
||||||
|
type = StringField()
|
||||||
|
plot_outline = StringField()
|
||||||
|
plots = ListField(StringField())
|
||||||
|
year = IntField()
|
||||||
|
|
||||||
|
class MediaFile(Document):
|
||||||
|
url = URLField()
|
||||||
|
path = StringField()
|
||||||
|
media = ReferenceField(Media)
|
||||||
|
mimetype = StringField()
|
||||||
|
resolution = StringField(choices=('480p', '720p', '1080p', 'native'), default="native")
|
||||||
|
|
||||||
|
class MediaPoster(Document):
|
||||||
|
poster = FileField()
|
||||||
|
media = ReferenceField(Media)
|
||||||
|
|
||||||
|
class Task(Document):
|
||||||
|
progress = FloatField(default=0)
|
||||||
|
state = StringField(choices=('starting', 'running', 'done'), default='starting')
|
||||||
|
creation_time = DateTimeField(default=datetime.datetime.now)
|
||||||
|
sub_tasks = ListField(ReferenceField('self'), default=list)
|
||||||
|
|
||||||
|
meta = {'allow_inheritance': True}
|
||||||
|
|
||||||
|
class TaskMetainfoDl(Task):
|
||||||
|
info_hash = StringField(required=True)
|
||||||
|
imdb_id = StringField()
|
||||||
|
|
||||||
|
class TaskImdbDl(Task):
|
||||||
|
imdb_id = StringField(required=True)
|
||||||
|
media = ReferenceField(Media)
|
||||||
|
|
||||||
|
class TaskTorrentDl(Task):
|
||||||
|
info_hash = StringField(required=True)
|
||||||
|
imdb_id = StringField()
|
||||||
|
media = ReferenceField(Media)
|
||||||
|
|
281
api/karumedia/tasks.py
Normal file
281
api/karumedia/tasks.py
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
from uwsgi_tasks import *
|
||||||
|
from .models import *
|
||||||
|
from time import sleep
|
||||||
|
from requests import get
|
||||||
|
import transmissionrpc
|
||||||
|
from pprint import pprint
|
||||||
|
from base64 import b64decode
|
||||||
|
from urllib.parse import urlencode, quote
|
||||||
|
import PTN
|
||||||
|
from imdbpie import Imdb
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import requests
|
||||||
|
import magic
|
||||||
|
import json
|
||||||
|
|
||||||
|
YTKEY = os.environ.get("YTKEY")
|
||||||
|
if not YTKEY:
|
||||||
|
error("YTKEY not set")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
default_trackers = [
|
||||||
|
'udp://glotorrents.pw:6969/announce',
|
||||||
|
'udp://tracker.openbittorrent.com:80',
|
||||||
|
'udp://tracker.coppersurfer.tk:6969',
|
||||||
|
'udp://tracker.leechers-paradise.org:6969',
|
||||||
|
'udp://p4p.arenabg.ch:1337',
|
||||||
|
'udp://tracker.internetwarriors.net:1337',
|
||||||
|
'udp://tracker.opentrackr.org:1337/announce'
|
||||||
|
]
|
||||||
|
|
||||||
|
r = get("https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt")
|
||||||
|
|
||||||
|
best_trackers = r.text
|
||||||
|
|
||||||
|
for tracker in best_trackers.split("\n"):
|
||||||
|
tracker = tracker.strip()
|
||||||
|
if tracker:
|
||||||
|
default_trackers.append(tracker)
|
||||||
|
|
||||||
|
def hash_to_magnet(infoHash, name=None, trackers=None):
|
||||||
|
try:
|
||||||
|
b64decode(infoHash)
|
||||||
|
except:
|
||||||
|
raise Exception("Invalid infoHash")
|
||||||
|
magnet = {
|
||||||
|
"dn": name,
|
||||||
|
"tr": list(default_trackers)
|
||||||
|
}
|
||||||
|
if not name:
|
||||||
|
del magnet["dn"]
|
||||||
|
if trackers:
|
||||||
|
magnet["tr"].extend(trackers)
|
||||||
|
return "magnet:?xt=urn:btih:{}&".format(infoHash) + urlencode(magnet, doseq=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
tc = transmissionrpc.Client("172.20.1.2", user="admin", password="minemetsa")
|
||||||
|
imdb = Imdb()
|
||||||
|
|
||||||
|
def guess_imdb_code(title):
|
||||||
|
info = PTN.parse(title)
|
||||||
|
if 'year' not in info:
|
||||||
|
print("No title year found in title")
|
||||||
|
results = imdb.search_for_title(info["title"])
|
||||||
|
if not results:
|
||||||
|
return None
|
||||||
|
if 'year' in info:
|
||||||
|
match = [movie for movie in results if movie["year"] == str(info["year"])]
|
||||||
|
if not match:
|
||||||
|
pprint(results)
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
match = match[0]["imdb_id"]
|
||||||
|
else:
|
||||||
|
match = results[0]["imdb_id"]
|
||||||
|
return match
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def metainfo_dl(task_id):
|
||||||
|
task = TaskMetainfoDl.objects.get(id=task_id)
|
||||||
|
|
||||||
|
magnet = hash_to_magnet(task.info_hash)
|
||||||
|
t = tc.add_torrent(magnet)
|
||||||
|
print(task.info_hash.lower())
|
||||||
|
print(t.hashString)
|
||||||
|
|
||||||
|
task.state = "running"
|
||||||
|
task.save()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
t = tc.get_torrent(t.hashString)
|
||||||
|
print(t.name, t.status, t.metadataPercentComplete*100, t.percentDone*100)
|
||||||
|
if t.metadataPercentComplete == 1:
|
||||||
|
break
|
||||||
|
task.progress = t.metadataPercentComplete*100
|
||||||
|
task.save()
|
||||||
|
sleep(1)
|
||||||
|
|
||||||
|
pprint(t.files())
|
||||||
|
t.stop()
|
||||||
|
|
||||||
|
if not task.imdb_id:
|
||||||
|
imdb_id = guess_imdb_code(t.name)
|
||||||
|
else:
|
||||||
|
imdb_id = task.imdb_id
|
||||||
|
print("imdb_id:", imdb_id)
|
||||||
|
|
||||||
|
try:
|
||||||
|
media = Media.objects.get(imdb_id=imdb_id)
|
||||||
|
print("Found existing media object:", media)
|
||||||
|
except DoesNotExist:
|
||||||
|
media = Media()
|
||||||
|
media.imdb_id = imdb_id
|
||||||
|
media.save()
|
||||||
|
print("Created a new media object:", media, media.imdb_id)
|
||||||
|
|
||||||
|
imdb_dl_task = TaskImdbDl(imdb_id=imdb_id)
|
||||||
|
imdb_dl_task.media = media
|
||||||
|
imdb_dl_task.save()
|
||||||
|
imdb_dl(str(imdb_dl_task.id))
|
||||||
|
|
||||||
|
torrent_dl_task = TaskTorrentDl(info_hash=t.hashString, imdb_id=imdb_id)
|
||||||
|
torrent_dl_task.media = media
|
||||||
|
torrent_dl_task.save()
|
||||||
|
torrent_dl(str(torrent_dl_task.id))
|
||||||
|
|
||||||
|
task.state = "done"
|
||||||
|
task.sub_tasks.append(imdb_dl_task)
|
||||||
|
task.sub_tasks.append(torrent_dl_task)
|
||||||
|
task.media = media
|
||||||
|
task.save()
|
||||||
|
|
||||||
|
@task
|
||||||
|
def imdb_dl(task_id):
|
||||||
|
task = TaskImdbDl.objects.get(id=task_id)
|
||||||
|
task.state = "running"
|
||||||
|
task.save()
|
||||||
|
print("imdb_id:", task.imdb_id)
|
||||||
|
try:
|
||||||
|
media = Media.objects.get(imdb_id=task.imdb_id)
|
||||||
|
print("Using existing media object:", media)
|
||||||
|
except DoesNotExist:
|
||||||
|
media = Media()
|
||||||
|
print("Creating a new media object")
|
||||||
|
media.imdb_id = task.imdb_id
|
||||||
|
|
||||||
|
title = imdb.get_title_by_id(task.imdb_id)
|
||||||
|
media.title = title.title
|
||||||
|
media.year = title.year
|
||||||
|
media.runtime = int(title.runtime)
|
||||||
|
media.genres = title.genres
|
||||||
|
media.mpa_rating = title.certification
|
||||||
|
media.release_date = title.release_date
|
||||||
|
media.type = title.type
|
||||||
|
media.plot_outline = title.plot_outline
|
||||||
|
media.plots = title.plots
|
||||||
|
media.rating = title.rating
|
||||||
|
media.save()
|
||||||
|
|
||||||
|
task.media = media
|
||||||
|
task.save()
|
||||||
|
|
||||||
|
|
||||||
|
params = {"key": YTKEY,
|
||||||
|
"part":"id", "maxResults":1,
|
||||||
|
"q":"{} ({}) trailer".format(media.title, media.year)}
|
||||||
|
r = requests.get("https://www.googleapis.com/youtube/v3/search", params=params)
|
||||||
|
media.yt_trailer_code = r.json()["items"][0]["id"]["videoId"]
|
||||||
|
media.save()
|
||||||
|
|
||||||
|
task.state = "done"
|
||||||
|
task.progress = 100
|
||||||
|
task.save()
|
||||||
|
|
||||||
|
|
||||||
|
def probe(vid_file_path):
|
||||||
|
''' Give a json from ffprobe command line
|
||||||
|
|
||||||
|
@vid_file_path : The absolute (full) path of the video file, string.
|
||||||
|
'''
|
||||||
|
if type(vid_file_path) != str:
|
||||||
|
raise Exception('Gvie ffprobe a full file path of the video')
|
||||||
|
return
|
||||||
|
|
||||||
|
command = ["ffprobe",
|
||||||
|
"-loglevel", "quiet",
|
||||||
|
"-print_format", "json",
|
||||||
|
"-show_format",
|
||||||
|
"-show_streams",
|
||||||
|
vid_file_path
|
||||||
|
]
|
||||||
|
|
||||||
|
pipe = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
|
out, err = pipe.communicate()
|
||||||
|
return json.loads(out)
|
||||||
|
|
||||||
|
|
||||||
|
def duration(vid_file_path):
|
||||||
|
''' Video's duration in seconds, return a float number
|
||||||
|
'''
|
||||||
|
_json = probe(vid_file_path)
|
||||||
|
pprint(_json)
|
||||||
|
|
||||||
|
if 'format' in _json:
|
||||||
|
if 'duration' in _json['format']:
|
||||||
|
return float(_json['format']['duration'])
|
||||||
|
|
||||||
|
if 'streams' in _json:
|
||||||
|
# commonly stream 0 is the video
|
||||||
|
for s in _json['streams']:
|
||||||
|
if 'duration' in s:
|
||||||
|
return float(s['duration'])
|
||||||
|
|
||||||
|
# if everything didn't happen,
|
||||||
|
# we got here because no single 'return' in the above happen.
|
||||||
|
raise Exception('I found no duration')
|
||||||
|
#return None
|
||||||
|
|
||||||
|
@task
|
||||||
|
def torrent_dl(task_id):
|
||||||
|
task = TaskTorrentDl.objects.get(id=task_id)
|
||||||
|
task.state = "running"
|
||||||
|
task.save()
|
||||||
|
|
||||||
|
t = tc.get_torrent(task.info_hash)
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
t = tc.get_torrent(task.info_hash)
|
||||||
|
print(t.name, t.status, t.metadataPercentComplete*100, t.percentDone*100)
|
||||||
|
if t.percentDone == 1:
|
||||||
|
break
|
||||||
|
task.progress = t.percentDone*100
|
||||||
|
task.save()
|
||||||
|
sleep(1)
|
||||||
|
|
||||||
|
if "imdb_id" in task:
|
||||||
|
try:
|
||||||
|
media = Media.objects.get(imdb_id=task.imdb_id)
|
||||||
|
except DoesNotExist:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
tc.rename_torrent_path(task.info_hash, t.name, f"{media.title} ({media.year})")
|
||||||
|
|
||||||
|
tc.move_torrent_data(task.info_hash, "/srv/media/Filmid")
|
||||||
|
|
||||||
|
with magic.Magic(flags=magic.MAGIC_MIME_TYPE) as m:
|
||||||
|
for file_id, file_data in t.files().items():
|
||||||
|
file_path = "/srv/media/Filmid/"+file_data["name"]
|
||||||
|
file_type = m.id_filename(file_path)
|
||||||
|
video_duration = None
|
||||||
|
if file_type.startswith("video"):
|
||||||
|
video_duration = duration(file_path)
|
||||||
|
|
||||||
|
print(file_path, file_type, video_duration)
|
||||||
|
if not MediaFile.objects(path = file_path):
|
||||||
|
media_file = MediaFile()
|
||||||
|
media_file.media = Media.objects.get(imdb_id=task.imdb_id)
|
||||||
|
media_file.path = file_path
|
||||||
|
media_file.url = f"http://media.arti.ee/Filmid/{quote(file_data['name'])}"
|
||||||
|
media_file.mimetype = file_type
|
||||||
|
media_file.resolution = "native"
|
||||||
|
media_file.save()
|
||||||
|
|
||||||
|
media = task.media
|
||||||
|
cover_path = f"/srv/media/Filmid/{media.title} ({media.year})/cover.jpg"
|
||||||
|
if not MediaFile.objects(media=media, path=cover_path):
|
||||||
|
subprocess.call(['wget', imdb.get_title_by_id(media.imdb_id).cover_url,
|
||||||
|
"-O", cover_path])
|
||||||
|
media_poster = MediaFile()
|
||||||
|
media_poster.path = cover_path
|
||||||
|
movie_name_and_year = quote(f"{media.title} ({media.year})")
|
||||||
|
media_poster.url = f"https://media.arti.ee/Filmid/{movie_name_and_year}/cover.jpg"
|
||||||
|
media_poster.save()
|
||||||
|
|
||||||
|
task.state = "done"
|
||||||
|
task.progress = 100
|
||||||
|
task.save()
|
@ -1,10 +1,24 @@
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
|
import datetime
|
||||||
|
|
||||||
from falcon import Request as FalconRequest
|
from falcon import Request as FalconRequest
|
||||||
from falcon import Response as FalconResponse
|
from falcon import Response as FalconResponse
|
||||||
from falcon.errors import HTTPBadRequest, HTTPMissingParam, HTTPError
|
from falcon.errors import HTTPBadRequest, HTTPMissingParam, HTTPError, HTTPNotFound
|
||||||
import falcon.status_codes as status
|
import falcon.status_codes as status
|
||||||
|
from bson.objectid import ObjectId
|
||||||
|
from mongoengine import DoesNotExist
|
||||||
|
|
||||||
|
class BSONDumps(json.JSONEncoder):
|
||||||
|
def default(self, obj):
|
||||||
|
if isinstance(obj, ObjectId):
|
||||||
|
return str(obj)
|
||||||
|
elif isinstance(obj, datetime.datetime):
|
||||||
|
return obj.timestamp()
|
||||||
|
# Let the base class default method raise the TypeError
|
||||||
|
return json.JSONEncoder.default(self, obj)
|
||||||
|
|
||||||
|
dumps = BSONDumps(indent=4).encode
|
||||||
|
|
||||||
|
|
||||||
class JsonRequest(FalconRequest):
|
class JsonRequest(FalconRequest):
|
||||||
@ -37,9 +51,12 @@ class JsonResponse(FalconResponse):
|
|||||||
@json.setter
|
@json.setter
|
||||||
def json(self, value):
|
def json(self, value):
|
||||||
self._json = value
|
self._json = value
|
||||||
self.body = json.dumps(value, indent=4)
|
self.body = dumps(value)
|
||||||
|
|
||||||
def error_handler(ex, req, resp, params):
|
def error_handler(ex, req, resp, params):
|
||||||
|
if type(ex).__name__ == DoesNotExist.__name__:
|
||||||
|
raise HTTPNotFound(title=type(ex).__name__, description=str(ex))
|
||||||
|
else:
|
||||||
raise HTTPBadRequest(type(ex).__name__, str(ex))
|
raise HTTPBadRequest(type(ex).__name__, str(ex))
|
||||||
|
|
||||||
class TODOException(HTTPError):
|
class TODOException(HTTPError):
|
||||||
|
@ -1 +1,13 @@
|
|||||||
falcon
|
CacheControl==0.11.7
|
||||||
|
falcon==1.1.0
|
||||||
|
filemagic==1.6
|
||||||
|
imdbpie==4.2.0
|
||||||
|
lockfile==0.12.2
|
||||||
|
mongoengine==0.11.0
|
||||||
|
parse-torrent-name==1.1.1
|
||||||
|
pymongo==3.4.0
|
||||||
|
python-mimeparse==1.6.0
|
||||||
|
requests==2.12.5
|
||||||
|
six==1.10.0
|
||||||
|
transmissionrpc==0.11
|
||||||
|
uwsgi-tasks==0.6.4
|
||||||
|
@ -14,6 +14,9 @@ http=:8080
|
|||||||
#static-index=index.html
|
#static-index=index.html
|
||||||
mount=/api/v1=wsgi.py
|
mount=/api/v1=wsgi.py
|
||||||
manage-script-name = true
|
manage-script-name = true
|
||||||
|
py-autoreload = 1
|
||||||
|
spooler = taskspool
|
||||||
|
spooler-processes = 3
|
||||||
|
|
||||||
|
|
||||||
[prod]
|
[prod]
|
||||||
|
Loading…
Reference in New Issue
Block a user