forked from rDrama/rDrama
commit
28695c459c
|
@ -76,6 +76,9 @@ app.config["SPAM_URL_SIMILARITY_THRESHOLD"] = float(environ.get("SPAM_URL_SIMILA
|
||||||
app.config["COMMENT_SPAM_SIMILAR_THRESHOLD"] = float(environ.get("COMMENT_SPAM_SIMILAR_THRESHOLD", 0.5))
|
app.config["COMMENT_SPAM_SIMILAR_THRESHOLD"] = float(environ.get("COMMENT_SPAM_SIMILAR_THRESHOLD", 0.5))
|
||||||
app.config["COMMENT_SPAM_COUNT_THRESHOLD"] = int(environ.get("COMMENT_SPAM_COUNT_THRESHOLD", 0.5))
|
app.config["COMMENT_SPAM_COUNT_THRESHOLD"] = int(environ.get("COMMENT_SPAM_COUNT_THRESHOLD", 0.5))
|
||||||
|
|
||||||
|
# how many coins are required to upload videos
|
||||||
|
app.config["VIDEO_COIN_REQUIREMENT"] = int(environ.get("VIDEO_COIN_REQUIREMENT", 0))
|
||||||
|
|
||||||
app.config["CACHE_REDIS_URL"] = environ.get("REDIS_URL").strip()
|
app.config["CACHE_REDIS_URL"] = environ.get("REDIS_URL").strip()
|
||||||
app.config["CACHE_DEFAULT_TIMEOUT"] = 60
|
app.config["CACHE_DEFAULT_TIMEOUT"] = 60
|
||||||
app.config["CACHE_KEY_PREFIX"] = "flask_caching_"
|
app.config["CACHE_KEY_PREFIX"] = "flask_caching_"
|
||||||
|
|
|
@ -45,6 +45,7 @@ class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
||||||
thumburl = Column(String)
|
thumburl = Column(String)
|
||||||
is_banned = Column(Boolean, default=False)
|
is_banned = Column(Boolean, default=False)
|
||||||
bannedfor = Column(Boolean)
|
bannedfor = Column(Boolean)
|
||||||
|
processing = Column(Boolean, default=False)
|
||||||
views = Column(Integer, default=0)
|
views = Column(Integer, default=0)
|
||||||
deleted_utc = Column(Integer, default=0)
|
deleted_utc = Column(Integer, default=0)
|
||||||
distinguish_level = Column(Integer, default=0)
|
distinguish_level = Column(Integer, default=0)
|
||||||
|
@ -400,6 +401,13 @@ class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
||||||
if self.url: return self.url.lower().endswith('.jpg') or self.url.lower().endswith('.png') or self.url.lower().endswith('.gif') or self.url.lower().endswith('.jpeg') or self.url.lower().endswith('?maxwidth=9999')
|
if self.url: return self.url.lower().endswith('.jpg') or self.url.lower().endswith('.png') or self.url.lower().endswith('.gif') or self.url.lower().endswith('.jpeg') or self.url.lower().endswith('?maxwidth=9999')
|
||||||
else: return False
|
else: return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_video(self) -> bool:
|
||||||
|
if self.url:
|
||||||
|
return self.url.startswith("https://i.imgur.com") and self.url.lower().endswith('.mp4')
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
def active_flags(self): return self.flags.count()
|
def active_flags(self): return self.flags.count()
|
||||||
|
|
|
@ -7,7 +7,16 @@ from .sanitize import *
|
||||||
from .const import *
|
from .const import *
|
||||||
|
|
||||||
|
|
||||||
def send_notification(vid, user, text):
|
def send_notification(vid, user, text, db=None):
|
||||||
|
|
||||||
|
# for when working outside request context
|
||||||
|
if isinstance(user, int):
|
||||||
|
uid = user
|
||||||
|
else:
|
||||||
|
uid = user.id
|
||||||
|
|
||||||
|
if not db:
|
||||||
|
db = g.db
|
||||||
|
|
||||||
text = text.replace('r/', 'r\/').replace('u/', 'u\/')
|
text = text.replace('r/', 'r\/').replace('u/', 'u\/')
|
||||||
text = text.replace("\n", "\n\n").replace("\n\n\n\n\n\n", "\n\n").replace("\n\n\n\n", "\n\n").replace("\n\n\n", "\n\n")
|
text = text.replace("\n", "\n\n").replace("\n\n\n\n\n\n", "\n\n").replace("\n\n\n\n", "\n\n").replace("\n\n\n", "\n\n")
|
||||||
|
@ -20,19 +29,19 @@ def send_notification(vid, user, text):
|
||||||
parent_submission=None,
|
parent_submission=None,
|
||||||
distinguish_level=6,
|
distinguish_level=6,
|
||||||
)
|
)
|
||||||
g.db.add(new_comment)
|
db.add(new_comment)
|
||||||
|
|
||||||
g.db.flush()
|
db.flush()
|
||||||
|
|
||||||
new_aux = CommentAux(id=new_comment.id,
|
new_aux = CommentAux(id=new_comment.id,
|
||||||
body=text,
|
body=text,
|
||||||
body_html=text_html,
|
body_html=text_html,
|
||||||
)
|
)
|
||||||
g.db.add(new_aux)
|
db.add(new_aux)
|
||||||
|
|
||||||
notif = Notification(comment_id=new_comment.id,
|
notif = Notification(comment_id=new_comment.id,
|
||||||
user_id=user.id)
|
user_id=uid)
|
||||||
g.db.add(notif)
|
db.add(notif)
|
||||||
|
|
||||||
|
|
||||||
def send_pm(vid, user, text):
|
def send_pm(vid, user, text):
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import requests
|
import requests
|
||||||
from os import environ
|
from os import environ, path, remove
|
||||||
from PIL import Image as IImage, ImageSequence
|
from PIL import Image as IImage, ImageSequence
|
||||||
import base64
|
import base64
|
||||||
from files.classes.images import *
|
from files.classes.images import *
|
||||||
from flask import g
|
from flask import g
|
||||||
|
from werkzeug.utils import secure_filename
|
||||||
|
|
||||||
CF_KEY = environ.get("CLOUDFLARE_KEY", "").strip()
|
CF_KEY = environ.get("CLOUDFLARE_KEY", "").strip()
|
||||||
CF_ZONE = environ.get("CLOUDFLARE_ZONE", "").strip()
|
CF_ZONE = environ.get("CLOUDFLARE_ZONE", "").strip()
|
||||||
|
@ -86,4 +87,36 @@ def upload_imgur(file=None, resize=False, png=False):
|
||||||
|
|
||||||
new_image = Image(text=url, deletehash=resp["deletehash"])
|
new_image = Image(text=url, deletehash=resp["deletehash"])
|
||||||
g.db.add(new_image)
|
g.db.add(new_image)
|
||||||
return(url)
|
return(url)
|
||||||
|
|
||||||
|
|
||||||
|
class UploadException(Exception):
|
||||||
|
"""Custom exception to raise if upload goes wrong"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def upload_video(file):
|
||||||
|
|
||||||
|
file_path = path.join("temp", secure_filename(file.filename))
|
||||||
|
file.save(file_path)
|
||||||
|
|
||||||
|
headers = {"Authorization": f"Client-ID {IMGUR_KEY}"}
|
||||||
|
with open(file_path, 'rb') as f:
|
||||||
|
try:
|
||||||
|
r = requests.post('https://api.imgur.com/3/upload', headers=headers, files={"video": f})
|
||||||
|
|
||||||
|
r.raise_for_status()
|
||||||
|
|
||||||
|
resp = r.json()['data']
|
||||||
|
except requests.HTTPError as e:
|
||||||
|
raise UploadException("Invalid video. Make sure it's 1 minute long or shorter.")
|
||||||
|
except Exception:
|
||||||
|
raise UploadException("Error, please try again later.")
|
||||||
|
finally:
|
||||||
|
remove(file_path)
|
||||||
|
|
||||||
|
link = resp['link']
|
||||||
|
img = Image(text=link, deletehash=resp['deletehash'])
|
||||||
|
g.db.add(img)
|
||||||
|
|
||||||
|
return link
|
||||||
|
|
|
@ -121,6 +121,11 @@ def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, filter_words='
|
||||||
|
|
||||||
posts = posts.filter_by(is_banned=False,stickied=False,private=False).filter(Submission.deleted_utc == 0)
|
posts = posts.filter_by(is_banned=False,stickied=False,private=False).filter(Submission.deleted_utc == 0)
|
||||||
|
|
||||||
|
if v:
|
||||||
|
posts = posts.filter(or_(Submission.processing == False, Submission.author_id == v.id))
|
||||||
|
else:
|
||||||
|
posts = posts.filter_by(processing=False)
|
||||||
|
|
||||||
if v and v.admin_level == 0:
|
if v and v.admin_level == 0:
|
||||||
blocking = g.db.query(
|
blocking = g.db.query(
|
||||||
UserBlock.target_id).filter_by(
|
UserBlock.target_id).filter_by(
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import time
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
import mistletoe
|
import mistletoe
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
@ -527,6 +528,44 @@ def filter_title(title):
|
||||||
|
|
||||||
return title
|
return title
|
||||||
|
|
||||||
|
|
||||||
|
IMGUR_KEY = environ.get("IMGUR_KEY", "").strip()
|
||||||
|
|
||||||
|
|
||||||
|
def check_processing_thread(v, post, link, db):
|
||||||
|
|
||||||
|
image_id = link.split('/')[-1].rstrip('.mp4')
|
||||||
|
headers = {"Authorization": f"Client-ID {IMGUR_KEY}"}
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# break on error to prevent zombie threads
|
||||||
|
try:
|
||||||
|
time.sleep(15)
|
||||||
|
|
||||||
|
req = requests.get(f"https://api.imgur.com/3/image/{image_id}", headers=headers)
|
||||||
|
|
||||||
|
status = req.json()['data']['processing']['status']
|
||||||
|
if status == 'completed':
|
||||||
|
post.processing = False
|
||||||
|
db.add(post)
|
||||||
|
|
||||||
|
send_notification(
|
||||||
|
NOTIFICATIONS_ACCOUNT,
|
||||||
|
v,
|
||||||
|
f"Your video has finished processing and your [post](/post/{post.id}) is now live.",
|
||||||
|
db=db
|
||||||
|
)
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
break
|
||||||
|
# just in case
|
||||||
|
elif status == 'failed':
|
||||||
|
print(f"video upload for post {post.id} failed")
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
@app.post("/submit")
|
@app.post("/submit")
|
||||||
@limiter.limit("6/minute")
|
@limiter.limit("6/minute")
|
||||||
@is_not_banned
|
@is_not_banned
|
||||||
|
@ -827,13 +866,72 @@ def submit_post(v):
|
||||||
abort(413)
|
abort(413)
|
||||||
|
|
||||||
file = request.files['file']
|
file = request.files['file']
|
||||||
if not file.content_type.startswith('image/'):
|
#if not file.content_type.startswith('image/'):
|
||||||
if request.headers.get("Authorization"): return {"error": f"Image files only"}, 400
|
# if request.headers.get("Authorization"): return {"error": f"Image files only"}, 400
|
||||||
else: return render_template("submit.html", v=v, error=f"Image files only.", title=title, body=request.form.get("body", "")), 400
|
# else: return render_template("submit.html", v=v, error=f"Image files only.", title=title, body=request.form.get("body", "")), 400
|
||||||
|
|
||||||
|
if not file.content_type.startswith(('image/', 'video/')):
|
||||||
|
if request.headers.get("Authorization"): return {"error": f"File type not allowed"}, 400
|
||||||
|
else: return render_template("submit.html", v=v, error=f"File type not allowed.", title=title, body=request.form.get("body", "")), 400
|
||||||
|
|
||||||
if 'pcm' in request.host: new_post.url = upload_ibb(file)
|
if file.content_type.startswith('video/') and v.coins < app.config["VIDEO_COIN_REQUIREMENT"] and v.admin_level < 1:
|
||||||
else: new_post.url = upload_imgur(file)
|
if request.headers.get("Authorization"):
|
||||||
|
return {
|
||||||
|
"error": f"You need at least {app.config['VIDEO_COIN_REQUIREMENT']} coins to upload videos"
|
||||||
|
}, 403
|
||||||
|
else:
|
||||||
|
return render_template(
|
||||||
|
"submit.html",
|
||||||
|
v=v,
|
||||||
|
error=f"You need at least {app.config['VIDEO_COIN_REQUIREMENT']} coins to upload videos.",
|
||||||
|
title=title,
|
||||||
|
body=request.form.get("body", "")
|
||||||
|
), 403
|
||||||
|
|
||||||
|
if 'pcm' in request.host:
|
||||||
|
if file.content_type.startswith('image/'):
|
||||||
|
new_post.url = upload_ibb(file)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
post_url = upload_video(file)
|
||||||
|
new_post.url = post_url
|
||||||
|
new_post.processing = True
|
||||||
|
gevent.spawn(check_processing_thread, v.id, new_post, post_url, g.db)
|
||||||
|
except UploadException as e:
|
||||||
|
if request.headers.get("Authorization"):
|
||||||
|
return {
|
||||||
|
"error": str(e),
|
||||||
|
}, 400
|
||||||
|
else:
|
||||||
|
return render_template(
|
||||||
|
"submit.html",
|
||||||
|
v=v,
|
||||||
|
error=str(e),
|
||||||
|
title=title,
|
||||||
|
body=request.form.get("body", "")
|
||||||
|
), 400
|
||||||
|
else:
|
||||||
|
if file.content_type.startswith('image/'):
|
||||||
|
new_post.url = upload_imgur(file)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
post_url = upload_video(file)
|
||||||
|
new_post.url = post_url
|
||||||
|
new_post.processing = True
|
||||||
|
gevent.spawn(check_processing_thread, v.id, new_post, post_url, g.db)
|
||||||
|
except UploadException as e:
|
||||||
|
if request.headers.get("Authorization"):
|
||||||
|
return {
|
||||||
|
"error": str(e),
|
||||||
|
}, 400
|
||||||
|
else:
|
||||||
|
return render_template(
|
||||||
|
"submit.html",
|
||||||
|
v=v,
|
||||||
|
error=str(e),
|
||||||
|
title=title,
|
||||||
|
body=request.form.get("body", "")
|
||||||
|
), 400
|
||||||
|
|
||||||
g.db.add(new_post)
|
g.db.add(new_post)
|
||||||
g.db.add(new_post.submission_aux)
|
g.db.add(new_post.submission_aux)
|
||||||
|
|
|
@ -36,6 +36,9 @@
|
||||||
<meta property="og:author" name="author" content="{{'@'+comment_info.author.username}}" />
|
<meta property="og:author" name="author" content="{{'@'+comment_info.author.username}}" />
|
||||||
<meta property="og:title" content="{{'@'+comment_info.author.username}} comments on {{p.title}} - {{'SITE_NAME' | app_config}}" />
|
<meta property="og:title" content="{{'@'+comment_info.author.username}} comments on {{p.title}} - {{'SITE_NAME' | app_config}}" />
|
||||||
<meta property="og:image" content="{% if p.is_image %}{{p.realurl(v)}}{% elif p.has_thumb%}{{p.thumb_url}}{% else %}{{'SITE_NAME' | app_config}}/assets/images/{{'SITE_NAME' | app_config}}/preview.gif{% endif %}" />
|
<meta property="og:image" content="{% if p.is_image %}{{p.realurl(v)}}{% elif p.has_thumb%}{{p.thumb_url}}{% else %}{{'SITE_NAME' | app_config}}/assets/images/{{'SITE_NAME' | app_config}}/preview.gif{% endif %}" />
|
||||||
|
{% if p.is_video %}
|
||||||
|
<meta property="og:video" content="{{ p.realurl(v) }}" />
|
||||||
|
{% endif %}
|
||||||
<meta property="og:url" content="{{comment_info.permalink | full_link}}" />
|
<meta property="og:url" content="{{comment_info.permalink | full_link}}" />
|
||||||
<meta property="og:site_name" content="{{request.host}}" />
|
<meta property="og:site_name" content="{{request.host}}" />
|
||||||
|
|
||||||
|
@ -62,6 +65,9 @@
|
||||||
<meta property="og:author" name="author" content="{{'@'+p.author.username}}" />
|
<meta property="og:author" name="author" content="{{'@'+p.author.username}}" />
|
||||||
<meta property="og:title" content="{{p.title}} - {{'SITE_NAME' | app_config}}" />
|
<meta property="og:title" content="{{p.title}} - {{'SITE_NAME' | app_config}}" />
|
||||||
<meta property="og:image" content="{% if p.is_image %}{{p.realurl(v)}}{% elif p.has_thumb%}{{p.thumb_url}}{% else %}{{'SITE_NAME' | app_config}}/assets/images/{{'SITE_NAME' | app_config}}/preview.gif{% endif %}" />
|
<meta property="og:image" content="{% if p.is_image %}{{p.realurl(v)}}{% elif p.has_thumb%}{{p.thumb_url}}{% else %}{{'SITE_NAME' | app_config}}/assets/images/{{'SITE_NAME' | app_config}}/preview.gif{% endif %}" />
|
||||||
|
{% if p.is_video %}
|
||||||
|
<meta property="og:video" content="{{ p.realurl(v) }}" />
|
||||||
|
{% endif %}
|
||||||
<meta property="og:url" content="{{p.permalink | full_link}}" />
|
<meta property="og:url" content="{{p.permalink | full_link}}" />
|
||||||
<meta property="og:site_name" content="{{request.host}}" />
|
<meta property="og:site_name" content="{{request.host}}" />
|
||||||
|
|
||||||
|
@ -256,6 +262,7 @@
|
||||||
{% if p.is_bot %} <i class="fad fa-robot text-info" data-toggle="tooltip" data-placement="bottom" data-original-title="Bot"></i>{% endif %}
|
{% if p.is_bot %} <i class="fad fa-robot text-info" data-toggle="tooltip" data-placement="bottom" data-original-title="Bot"></i>{% endif %}
|
||||||
{% if p.over_18 %}<span class="badge badge-danger text-small-extra mr-1">+18</span>{% endif %}
|
{% if p.over_18 %}<span class="badge badge-danger text-small-extra mr-1">+18</span>{% endif %}
|
||||||
{% if p.private %}<span class="badge border-warning border-1 text-small-extra">Draft</span>{% endif %}
|
{% if p.private %}<span class="badge border-warning border-1 text-small-extra">Draft</span>{% endif %}
|
||||||
|
{% if p.processing %}<span class="badge border-warning border-1 text-small-extra">uploading...</span>{% endif %}
|
||||||
{% if p.active_flags %}<a class="btn btn-primary" href="javascript:void(0)" style="padding:1px 5px; font-size:10px;" onclick="document.getElementById('flaggers').classList.toggle('d-none')">{{p.active_flags}} Reports</a>{% endif %}
|
{% if p.active_flags %}<a class="btn btn-primary" href="javascript:void(0)" style="padding:1px 5px; font-size:10px;" onclick="document.getElementById('flaggers').classList.toggle('d-none')">{{p.active_flags}} Reports</a>{% endif %}
|
||||||
{% if p.author.verified %}<i class="fas fa-badge-check align-middle ml-1" style="color:#1DA1F2" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="{{p.author.verified}}"></i>
|
{% if p.author.verified %}<i class="fas fa-badge-check align-middle ml-1" style="color:#1DA1F2" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="{{p.author.verified}}"></i>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -301,7 +308,7 @@
|
||||||
<iframe src="{{streamurl}}" width="100%" height="80" frameBorder="0" allowtransparency="true" allow="encrypted-media"></iframe>
|
<iframe src="{{streamurl}}" width="100%" height="80" frameBorder="0" allowtransparency="true" allow="encrypted-media"></iframe>
|
||||||
<pre></pre>
|
<pre></pre>
|
||||||
|
|
||||||
{% elif not p.embed_url and not p.is_image %}
|
{% elif not p.embed_url and not p.is_image and not p.is_video %}
|
||||||
<a rel="nofollow noopener noreferrer" href="{{p.realurl(v)}}" {% if not v or v.newtabexternal %}target="_blank"{% endif %}>
|
<a rel="nofollow noopener noreferrer" href="{{p.realurl(v)}}" {% if not v or v.newtabexternal %}target="_blank"{% endif %}>
|
||||||
<div class="d-flex d-md-none justify-content-between align-items-center border rounded p-2{% if p.realbody(v) %} mb-3{% endif %}">
|
<div class="d-flex d-md-none justify-content-between align-items-center border rounded p-2{% if p.realbody(v) %} mb-3{% endif %}">
|
||||||
<span>{{p.domain|truncate(30, True)}}</span>
|
<span>{{p.domain|truncate(30, True)}}</span>
|
||||||
|
@ -321,6 +328,15 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<pre></pre>
|
<pre></pre>
|
||||||
|
{% elif p.is_video %}
|
||||||
|
<div class="row no-gutters">
|
||||||
|
<div class="col">
|
||||||
|
<video controls preload="metadata" style="max-width: 100%">
|
||||||
|
<source src="{{ p.realurl(v) }}" type="video/mp4">
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<pre></pre>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{p.realbody(v) | safe}}
|
{{p.realbody(v) | safe}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -497,7 +513,7 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if not p.is_image %}
|
{% if not p.is_image and not p.is_video %}
|
||||||
<div class="row no-gutters d-block d-md-none">
|
<div class="row no-gutters d-block d-md-none">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<a {% if not v or v.newtabexternal %}target="_blank"{% endif %} rel="nofollow noopener noreferrer" href="{{p.realurl(v)}}"></a>
|
<a {% if not v or v.newtabexternal %}target="_blank"{% endif %} rel="nofollow noopener noreferrer" href="{{p.realurl(v)}}"></a>
|
||||||
|
|
|
@ -69,10 +69,10 @@
|
||||||
<img loading="lazy" src="{{p.thumb_url}}" class="post-img">
|
<img loading="lazy" src="{{p.thumb_url}}" class="post-img">
|
||||||
</a>
|
</a>
|
||||||
{% elif p.is_image %}
|
{% elif p.is_image %}
|
||||||
<a href="javascript:void(0)" class="expandable-image" data-toggle="modal" data-target="#expandImageModal" data-url="{{p.realurl(v)}}">
|
<a href="javascript:void(0)" class="expandable-image" data-toggle="modal" data-target="#expandImageModal" data-url="{{p.realurl(v)}}" onclick="expandDesktopImage('{{ p.realurl(v) }}')">
|
||||||
<img loading="lazy" src="{{p.thumb_url}}" class="post-img">
|
<img loading="lazy" src="{{p.thumb_url}}" class="post-img">
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% elif not p.is_video %}
|
||||||
<a {% if not v or v.newtabexternal %}target="_blank"{% endif %} rel="nofollow noopener noreferrer" href="{{p.realurl(v)}}">
|
<a {% if not v or v.newtabexternal %}target="_blank"{% endif %} rel="nofollow noopener noreferrer" href="{{p.realurl(v)}}">
|
||||||
<img loading="lazy" src="{{p.thumb_url}}" class="post-img">
|
<img loading="lazy" src="{{p.thumb_url}}" class="post-img">
|
||||||
</a>
|
</a>
|
||||||
|
@ -104,6 +104,7 @@
|
||||||
{% if p.is_blocking %}<i class="fas fa-user-minus text-warning" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="You're blocking this user, but you can see this post because {{'it\'s an admin post' if p.distinguish_level else 'you\'re an admin'}}."></i>{% endif %}
|
{% if p.is_blocking %}<i class="fas fa-user-minus text-warning" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="You're blocking this user, but you can see this post because {{'it\'s an admin post' if p.distinguish_level else 'you\'re an admin'}}."></i>{% endif %}
|
||||||
{% if p.is_blocked %}<i class="fas fa-user-minus text-danger" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="This user is blocking you."></i>{% endif %}
|
{% if p.is_blocked %}<i class="fas fa-user-minus text-danger" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="This user is blocking you."></i>{% endif %}
|
||||||
{% if p.private %}<span class="badge border-warning border-1 text-small-extra">Draft</span>{% endif %}
|
{% if p.private %}<span class="badge border-warning border-1 text-small-extra">Draft</span>{% endif %}
|
||||||
|
{% if p.processing %}<span class="badge border-warning border-1 text-small-extra">uploading...</span>{% endif %}
|
||||||
{% if p.active_flags %}<a class="btn btn-primary" href="javascript:void(0)" style="padding:1px 5px; font-size:10px;" onclick="document.getElementById('flaggers-{{p.id}}').classList.toggle('d-none')">{{p.active_flags}} Reports</a>{% endif %}
|
{% if p.active_flags %}<a class="btn btn-primary" href="javascript:void(0)" style="padding:1px 5px; font-size:10px;" onclick="document.getElementById('flaggers-{{p.id}}').classList.toggle('d-none')">{{p.active_flags}} Reports</a>{% endif %}
|
||||||
{% if p.author.verified %}<i class="fas fa-badge-check align-middle ml-1" style="color:#1DA1F2" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="{{p.author.verified}}"></i>
|
{% if p.author.verified %}<i class="fas fa-badge-check align-middle ml-1" style="color:#1DA1F2" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="{{p.author.verified}}"></i>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -392,6 +393,14 @@
|
||||||
<img loading="lazy" src="{{p.url}}" class="img-fluid" style="max-height:500px;" alt="Unable to load image">
|
<img loading="lazy" src="{{p.url}}" class="img-fluid" style="max-height:500px;" alt="Unable to load image">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
{% elif p.is_video %}
|
||||||
|
<a href="javascript:void(0)">
|
||||||
|
<div style="text-align: center" class="mt-4">
|
||||||
|
<video controls preload="metadata" style="max-width: 100%">
|
||||||
|
<source src="{{p.realurl(v)}}" type="video/mp4">
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
{% elif p.embed_url and "youtu" in p.domain or "streamable.com/" in p.url %}
|
{% elif p.embed_url and "youtu" in p.domain or "streamable.com/" in p.url %}
|
||||||
<div style="text-align: center" class="mt-3 mb-4">
|
<div style="text-align: center" class="mt-3 mb-4">
|
||||||
<iframe src="{{p.embed_url}}" frameborder="0" width="600" height="337" allow="fullscreen"></iframe>
|
<iframe src="{{p.embed_url}}" frameborder="0" width="600" height="337" allow="fullscreen"></iframe>
|
||||||
|
|
|
@ -330,16 +330,17 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="image-upload-block">
|
<div id="image-upload-block">
|
||||||
<div><label class="mt-3">Image Upload</label></div>
|
<div><label class="mt-3">Attachment Upload</label></div>
|
||||||
|
|
||||||
<img loading="lazy" id="image-preview" class="w-100 d-block">
|
<img loading="lazy" id="image-preview" class="w-100 d-block">
|
||||||
|
|
||||||
<label class="btn btn-secondary m-0" for="file-upload">
|
<label class="btn btn-secondary m-0" for="file-upload">
|
||||||
<div id="filename-show">Select Image</div>
|
<div id="filename-show">Select File</div>
|
||||||
<input id="file-upload" type="file" name="file" accept="image/*" hidden>
|
<input id="file-upload" type="file" name="file" accept="image/*, video/*" hidden>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<small class="form-text text-muted">Images uploaded will be public. Optional if you have text.</small>
|
<small class="form-text text-muted">Optional if you have text.</small>
|
||||||
|
<small class="form-text text-muted">You can upload videos up to 1 minute long if you have at least {{ 'VIDEO_COIN_REQUIREMENT' | app_config }} {{ 'COINS_NAME' | app_config }}{% if v.admin_level > 1 %} or are an admin{% endif %}.</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue