Merge pull request 'master' (#1) from rDrama/rDrama:master into master
Reviewed-on: TheDunceonMaster/rDrama#1pull/138/head
|
@ -145,7 +145,7 @@ lite-youtube {
|
|||
margin: 14px 0 0 0!important;
|
||||
}
|
||||
|
||||
img[alt^="![]("] {
|
||||
img[alt^="![]("], .img {
|
||||
height: 150px;
|
||||
width: 90%;
|
||||
-o-object-fit: contain;
|
||||
|
|
|
@ -204,6 +204,7 @@
|
|||
.fa-lock:before{content:"\f023"}
|
||||
.fa-lock-open:before{content:"\f3c1"}
|
||||
.fa-down:before{content:"\f354"}
|
||||
.fa-shield-virus:before{content:"\e06c"}
|
||||
|
||||
button {
|
||||
background: none;
|
||||
|
@ -1836,8 +1837,7 @@ button.close {
|
|||
padding: 0.75rem;
|
||||
}
|
||||
.modal-open {
|
||||
overflow: auto !important;
|
||||
padding-right: 0 !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
.modal-open .modal {
|
||||
overflow-x: hidden;
|
||||
|
@ -5121,11 +5121,9 @@ pre .com, code .com {
|
|||
}
|
||||
.comment-section {
|
||||
background-color: var(--gray-600);
|
||||
}
|
||||
.comment-section > .comment {
|
||||
padding-left: 12px;
|
||||
}
|
||||
.comment {
|
||||
padding-left: 0;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
.comment.collapsed .user-info {
|
||||
|
@ -5226,6 +5224,7 @@ span.green {
|
|||
background-color: var(--white) !important;
|
||||
font-weight: 600 !important;
|
||||
padding: 1px 3px 1px 3px;
|
||||
cursor: default;
|
||||
}
|
||||
.spoiler:hover, spoiler:hover {
|
||||
color: var(--gray) !important;
|
||||
|
@ -5243,10 +5242,6 @@ span.green {
|
|||
padding-left: 0 !important;
|
||||
}
|
||||
}
|
||||
.comment .comment-collapse-desktop {
|
||||
padding-right: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.comment .comment-collapse-desktop:hover {
|
||||
border-left-color: var(--white) !important;
|
||||
}
|
||||
|
@ -5319,7 +5314,7 @@ span.green {
|
|||
border-radius: 5px !important;
|
||||
color: white !important;
|
||||
}
|
||||
.patron[style="background-color:#FFFFFF;"] {
|
||||
.patron[style*="background-color:#ffffff"] {
|
||||
color: black !important;
|
||||
}
|
||||
.container, .container-fluid {
|
||||
|
@ -6915,13 +6910,13 @@ div.markdown {
|
|||
resize: both;
|
||||
display: inline-block;
|
||||
overflow: auto;
|
||||
max-height: 100vh !important;
|
||||
max-height: 700vh !important;
|
||||
max-width: 100vw !important;
|
||||
}
|
||||
.resizable > video {
|
||||
height: 99% !important;
|
||||
width: 99% !important;
|
||||
max-height: 100vh !important;
|
||||
max-height: 70vh !important;
|
||||
max-width: 100vw !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
@ -7133,11 +7128,7 @@ body {
|
|||
line-height: 2.3;
|
||||
}
|
||||
|
||||
.modal, body, nav {
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
.dm_img[alt^="![]("] {
|
||||
.dm_img {
|
||||
width: 200px;
|
||||
max-height: 100vh !important;
|
||||
}
|
||||
|
@ -7206,6 +7197,10 @@ input[type=number] {
|
|||
min-height: 100px;
|
||||
}
|
||||
|
||||
#note {
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
.collapsed .showmore-text
|
||||
{
|
||||
display: none;
|
||||
|
@ -7215,3 +7210,16 @@ input[type=number] {
|
|||
min-width: 30px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.comment .comment-collapse-desktop {
|
||||
padding-right: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
@media (max-width: 767.98px) {
|
||||
.comment .comment-collapse-desktop {
|
||||
padding-right: 10px;
|
||||
}
|
||||
blockquote {
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2819,6 +2819,18 @@
|
|||
"joke"
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"name": "taycrying",
|
||||
"class": "Tay",
|
||||
"tags": [
|
||||
"taylor",
|
||||
"swift",
|
||||
"sad",
|
||||
"hysterical",
|
||||
"ellen"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "taysneer",
|
||||
"class": "Tay",
|
||||
|
@ -7551,6 +7563,28 @@
|
|||
"crime"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "drafts",
|
||||
"tags": [
|
||||
"that",
|
||||
"should",
|
||||
"should've",
|
||||
"shouldve",
|
||||
"have",
|
||||
"stayed",
|
||||
"in",
|
||||
"the",
|
||||
"boo",
|
||||
"thathoeoverthere",
|
||||
"thot",
|
||||
"girl",
|
||||
"cringe",
|
||||
"reaction",
|
||||
"gif",
|
||||
"animated"
|
||||
],
|
||||
"class": "Misc"
|
||||
},
|
||||
{
|
||||
"name": "capytalking",
|
||||
"tags": [
|
||||
|
|
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 9.7 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 398 KiB |
Before Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 14 KiB |
|
@ -139,7 +139,7 @@ function buy(mb) {
|
|||
xhr[0].onload = function() {
|
||||
let data
|
||||
try {data = JSON.parse(xhr[0].response)}
|
||||
catch(e) {console.log(e)}
|
||||
catch(e) {console.error(e)}
|
||||
success = xhr[0].status >= 200 && xhr[0].status < 300;
|
||||
showToast(success, getMessageFromJsonData(success, data), true);
|
||||
if (success) {
|
||||
|
|
|
@ -9,7 +9,7 @@ function banModal(link, name, fullname, cls) {
|
|||
xhr[0].onload = function() {
|
||||
let data
|
||||
try {data = JSON.parse(xhr[0].response)}
|
||||
catch(e) {console.log(e)}
|
||||
catch(e) {console.error(e)}
|
||||
success = xhr[0].status >= 200 && xhr[0].status < 300;
|
||||
showToast(success, getMessageFromJsonData(success, data));
|
||||
document.getElementById(`unban-${fullname}`).classList.toggle(cls);
|
||||
|
@ -31,7 +31,7 @@ function chudModal(link, name, fullname, cls) {
|
|||
xhr[0].onload = function() {
|
||||
let data
|
||||
try {data = JSON.parse(xhr[0].response)}
|
||||
catch(e) {console.log(e)}
|
||||
catch(e) {console.error(e)}
|
||||
success = xhr[0].status >= 200 && xhr[0].status < 300;
|
||||
showToast(success, getMessageFromJsonData(success, data));
|
||||
document.getElementById(`unchud-${fullname}`).classList.toggle(cls);
|
||||
|
|
|
@ -97,33 +97,31 @@ for (const element of TH) {
|
|||
element.addEventListener('click', () => {sort_table(element)});
|
||||
}
|
||||
|
||||
const btns_to_disable = document.querySelectorAll('[type="submit"]')
|
||||
for (const element of btns_to_disable) {
|
||||
element.addEventListener('click', () => {disable_btn(element)})
|
||||
}
|
||||
|
||||
function disable_btn(t) {
|
||||
if (!t.classList.contains('disabled')) {
|
||||
const isShopConfirm = t.id.startsWith('buy1-') || t.id.startsWith('buy2-') || t.id.startsWith('giveaward')
|
||||
|
||||
if (!isShopConfirm) {
|
||||
t.classList.add('disabled');
|
||||
|
||||
setTimeout(() => {
|
||||
t.disabled = true;
|
||||
}, 0.0000000000000000001);
|
||||
}, 0.1);
|
||||
|
||||
setTimeout(() => {
|
||||
t.classList.remove("disabled");
|
||||
t.disabled = false;
|
||||
}, 1000);
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function register_new_elements(e) {
|
||||
const showmores = document.getElementsByClassName('showmore')
|
||||
for (const element of showmores) {
|
||||
element.onclick = () => {showmore(element)};
|
||||
}
|
||||
|
||||
const onclick = e.querySelectorAll('[data-onclick]');
|
||||
for (const element of onclick) {
|
||||
element.onclick = () => {
|
||||
execute(element, 'onclick')
|
||||
disable_btn(element)
|
||||
};
|
||||
}
|
||||
|
||||
const oninput = e.querySelectorAll('[data-oninput]');
|
||||
for (const element of oninput) {
|
||||
element.oninput = () => {execute(element, 'oninput')};
|
||||
|
@ -139,52 +137,63 @@ function register_new_elements(e) {
|
|||
element.onchange = () => {execute(element, 'onchange')};
|
||||
}
|
||||
|
||||
const popover_triggers = document.getElementsByClassName('user-name');
|
||||
for (const element of popover_triggers) {
|
||||
element.onclick = (e) => {
|
||||
if (!(e.ctrlKey || e.metaKey || e.shiftKey || e.altKey))
|
||||
e.preventDefault();
|
||||
};
|
||||
}
|
||||
|
||||
const expandable = document.querySelectorAll('.in-comment-image, img[alt^="![]("]');
|
||||
for (const element of expandable) {
|
||||
element.onclick = () => {expandImage()};
|
||||
}
|
||||
|
||||
const toggleelement = e.querySelectorAll('[data-toggleelement]');
|
||||
for (const element of toggleelement) {
|
||||
element.addEventListener('click', () => {
|
||||
document.getElementById(element.dataset.toggleelement).classList.toggle(element.dataset.toggleattr);
|
||||
});
|
||||
}
|
||||
|
||||
const file_inputs = document.querySelectorAll('input[multiple="multiple"]')
|
||||
for (const input of file_inputs) {
|
||||
input.onchange = () => {handle_files(input, input.files)};
|
||||
}
|
||||
|
||||
const remove_files = document.querySelectorAll('button.remove-files')
|
||||
for (const element of remove_files) {
|
||||
element.onclick = () => {cancel_files(element)};
|
||||
const onclick = e.querySelectorAll('[data-onclick]');
|
||||
for (const element of onclick) {
|
||||
element.onclick = () => {execute(element, 'onclick')};
|
||||
}
|
||||
|
||||
const data_url = document.querySelectorAll('[data-url]');
|
||||
for (const element of data_url) {
|
||||
if (element.dataset.nonce != nonce) {
|
||||
console.log("Nonce check failed!")
|
||||
continue
|
||||
}
|
||||
element.addEventListener('click', () => {
|
||||
document.getElementById('giveaward').dataset.action = element.dataset.url
|
||||
const textareas = e.getElementsByTagName('textarea')
|
||||
for (const element of textareas) {
|
||||
autoExpand(element)
|
||||
element.addEventListener('input', () => {
|
||||
autoExpand(element)
|
||||
});
|
||||
}
|
||||
|
||||
const btns_to_disable = document.querySelectorAll('[type="submit"]')
|
||||
for (const btn of btns_to_disable) {
|
||||
btn.addEventListener('click', () => {disable_btn(btn)})
|
||||
}
|
||||
}
|
||||
|
||||
register_new_elements(document);
|
||||
bs_trigger(document);
|
||||
|
||||
|
||||
document.addEventListener("click", function(e){
|
||||
const element = e.target
|
||||
|
||||
if (element instanceof HTMLImageElement && (element.alt.startsWith('![](')) || element.classList.contains('in-comment-image') || element.classList.contains('img')) {
|
||||
expandImage()
|
||||
}
|
||||
else if (element.classList.contains('showmore')) {
|
||||
showmore(element)
|
||||
}
|
||||
else if (element.parentElement.classList.contains('user-name')) {
|
||||
if (!(e.ctrlKey || e.metaKey || e.shiftKey || e.altKey))
|
||||
e.preventDefault();
|
||||
}
|
||||
else if (element.classList.contains('remove-files')) {
|
||||
cancel_files(element)
|
||||
}
|
||||
else if (element.dataset.url) {
|
||||
if (element.dataset.nonce != nonce) {
|
||||
console.log("Nonce check failed!")
|
||||
return
|
||||
}
|
||||
document.getElementById('giveaward').dataset.action = element.dataset.url
|
||||
}
|
||||
|
||||
|
||||
if (element.dataset.toggleelement) {
|
||||
document.querySelector(element.dataset.toggleelement).classList.toggle(element.dataset.toggleattr);
|
||||
}
|
||||
});
|
||||
|
||||
const inputs = document.querySelectorAll('input[type="number"]')
|
||||
for (const input of inputs) {
|
||||
input.onkeyup = () => {
|
||||
console.log(1)
|
||||
if (parseInt(input.value) > parseInt(input.max)) input.value = input.max;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ document.addEventListener('shown.bs.popover', (e) => {
|
|||
popover.getElementsByClassName('pop-coins')[0].innerHTML = author["coins"]
|
||||
popover.getElementsByClassName('pop-view_more')[0].href = author["url"]
|
||||
popover.getElementsByClassName('pop-created-date')[0].innerHTML = author["created_date"]
|
||||
popover.getElementsByClassName('pop-id')[0].innerHTML = author["id"]
|
||||
})
|
||||
|
||||
function post(url) {
|
||||
|
@ -86,11 +87,12 @@ function poll_vote_1(oid, parentid, kind) {
|
|||
curr.value = full_oid
|
||||
}
|
||||
|
||||
function bet_vote(t, oid) {
|
||||
postToast(t, `/vote/post/option/${oid}`,
|
||||
function bet_vote(t, oid, kind) {
|
||||
postToast(t, `/vote/${kind}/option/${oid}`,
|
||||
{
|
||||
},
|
||||
() => {
|
||||
t.disabled = true;
|
||||
for(let el of document.getElementsByClassName('bet')) {
|
||||
el.disabled = true;
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ function post_reply(id){
|
|||
|
||||
let data
|
||||
try {data = JSON.parse(xhr[0].response)}
|
||||
catch(e) {console.log(e)}
|
||||
catch(e) {console.error(e)}
|
||||
if (data && data["comment"]) {
|
||||
const comments = document.getElementById('replies-of-c_' + id);
|
||||
const comment = data["comment"].replace(/data-src/g, 'src').replace(/data-cfsrc/g, 'src').replace(/style="display:none;visibility:hidden;"/g, '').replace(/data-nonce=".*?"/g, `data-nonce="${nonce}"`);
|
||||
|
@ -160,10 +160,8 @@ function post_reply(id){
|
|||
} else {
|
||||
showToast(false, getMessageFromJsonData(false, data));
|
||||
}
|
||||
setTimeout(() => {
|
||||
btn.disabled = false;
|
||||
btn.classList.remove('disabled');
|
||||
}, 2000);
|
||||
}
|
||||
xhr[0].send(xhr[1]);
|
||||
}
|
||||
|
@ -193,7 +191,7 @@ function comment_edit(id){
|
|||
|
||||
let data
|
||||
try {data = JSON.parse(xhr[0].response)}
|
||||
catch(e) {console.log(e)}
|
||||
catch(e) {console.error(e)}
|
||||
if (data && data["comment"]) {
|
||||
commentForm=document.getElementById('comment-text-'+id);
|
||||
commentForm.innerHTML = data["comment"].replace(/data-src/g, 'src').replace(/data-cfsrc/g, 'src').replace(/style="display:none;visibility:hidden;"/g, '').replace(/data-nonce=".*?"/g, `data-nonce="${nonce}"`)
|
||||
|
@ -213,10 +211,8 @@ function comment_edit(id){
|
|||
else {
|
||||
showToast(false, getMessageFromJsonData(false, data));
|
||||
}
|
||||
setTimeout(() => {
|
||||
btn.disabled = false;
|
||||
btn.classList.remove('disabled');
|
||||
}, 1000);
|
||||
}
|
||||
xhr[0].send(xhr[1]);
|
||||
}
|
||||
|
@ -252,7 +248,7 @@ function post_comment(fullname, hide){
|
|||
|
||||
let data
|
||||
try {data = JSON.parse(xhr.response)}
|
||||
catch(e) {console.log(e)}
|
||||
catch(e) {console.error(e)}
|
||||
if (data && data["comment"]) {
|
||||
if (hide) document.getElementById(hide).classList.add('d-none');
|
||||
|
||||
|
@ -284,10 +280,8 @@ function post_comment(fullname, hide){
|
|||
}
|
||||
else {
|
||||
showToast(false, getMessageFromJsonData(false, data));
|
||||
setTimeout(() => {
|
||||
btn.disabled = false;
|
||||
btn.classList.remove('disabled');
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
xhr.send(form)
|
||||
|
@ -315,7 +309,7 @@ function handle_action(type, cid, thing) {
|
|||
xhr.onload=function(){
|
||||
let data
|
||||
try {data = JSON.parse(xhr.response)}
|
||||
catch(e) {console.log(e)}
|
||||
catch(e) {console.error(e)}
|
||||
if (data && data["response"]) {
|
||||
const element = document.getElementById(`${type}-${cid}`);
|
||||
element.innerHTML = data["response"].replace(/data-nonce=".*?"/g, `data-nonce="${nonce}"`)
|
||||
|
@ -323,13 +317,11 @@ function handle_action(type, cid, thing) {
|
|||
} else {
|
||||
showToast(false, getMessageFromJsonData(false, data));
|
||||
}
|
||||
setTimeout(() => {
|
||||
for (const btn of btns)
|
||||
{
|
||||
btn.disabled = false;
|
||||
btn.classList.remove('disabled');
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
xhr.send(form)
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@ function postToast(t, url, data, extraActionsOnSuccess, method="POST") {
|
|||
let result
|
||||
let message;
|
||||
let success = xhr[0].status >= 200 && xhr[0].status < 300;
|
||||
if (success && extraActionsOnSuccess) result = extraActionsOnSuccess(xhr[0]);
|
||||
if (typeof result == "string") {
|
||||
message = result;
|
||||
} else {
|
||||
|
@ -65,17 +64,10 @@ function postToast(t, url, data, extraActionsOnSuccess, method="POST") {
|
|||
t.disabled = false;
|
||||
t.classList.remove("disabled");
|
||||
}
|
||||
if (success && extraActionsOnSuccess) result = extraActionsOnSuccess(xhr[0]);
|
||||
return success;
|
||||
};
|
||||
xhr[0].send(xhr[1]);
|
||||
|
||||
if (!isShopConfirm)
|
||||
{
|
||||
setTimeout(() => {
|
||||
t.disabled = false;
|
||||
t.classList.remove("disabled");
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
function postToastReload(t, url, method="POST") {
|
||||
|
@ -153,14 +145,6 @@ function autoExpand(field) {
|
|||
window.scrollTo(xpos,ypos);
|
||||
};
|
||||
|
||||
const textareas = document.getElementsByTagName('textarea')
|
||||
for (const element of textareas) {
|
||||
autoExpand(element)
|
||||
element.addEventListener('input', () => {
|
||||
autoExpand(element)
|
||||
});
|
||||
}
|
||||
|
||||
function smoothScrollTop()
|
||||
{
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
|
@ -186,6 +170,8 @@ function formkey() {
|
|||
else return null;
|
||||
}
|
||||
|
||||
const expandImageModal = document.getElementById('expandImageModal')
|
||||
|
||||
function expandImage(url) {
|
||||
const e = this.event
|
||||
if(e.ctrlKey || e.metaKey || e.shiftKey || e.altKey)
|
||||
|
@ -199,7 +185,7 @@ function expandImage(url) {
|
|||
document.getElementById("desktop-expanded-image").src = url.replace("200w.webp", "giphy.webp");
|
||||
document.getElementById("desktop-expanded-image-wrap-link").href = url.replace("200w.webp", "giphy.webp");
|
||||
|
||||
bootstrap.Modal.getOrCreateInstance(document.getElementById('expandImageModal')).show();
|
||||
bootstrap.Modal.getOrCreateInstance(expandImageModal).show();
|
||||
};
|
||||
|
||||
function bs_trigger(e) {
|
||||
|
@ -240,15 +226,11 @@ function escapeHTML(unsafe) {
|
|||
}
|
||||
|
||||
function showmore(t) {
|
||||
let div = t
|
||||
while (!(div.id && (div.id.startsWith('comment-text-') || div.id == 'post-text'))){
|
||||
div = div.parentElement
|
||||
}
|
||||
div = div.parentElement
|
||||
div = t.parentElement.parentElement.parentElement
|
||||
|
||||
let text = div.getElementsByTagName('d')[0]
|
||||
if (!text) text = div.getElementsByClassName('showmore-text')[0]
|
||||
if (!text) text = div.getElementsByClassName('d-none')[0]
|
||||
if (!text) text = div.querySelector('div.d-none')
|
||||
|
||||
text.classList.add('showmore-text')
|
||||
|
||||
|
@ -478,31 +460,17 @@ function handle_files(input, newfiles) {
|
|||
return
|
||||
}
|
||||
|
||||
if (!span.innerHTML) span.innerHTML = ' '
|
||||
|
||||
if (ta.value && !ta.value.endsWith('\n')) {
|
||||
ta.value += '\n'
|
||||
}
|
||||
|
||||
|
||||
const selection_end = ta.selectionEnd
|
||||
const selected_text = ta.value.substring(ta.selectionStart, selection_end);
|
||||
if (!span.textContent) span.textContent = ' '
|
||||
|
||||
for (const file of newfiles) {
|
||||
oldfiles[ta.id].push(file)
|
||||
if (span.innerHTML != ' ') span.innerHTML += ', '
|
||||
span.innerHTML += file.name.substr(0, 30);
|
||||
if (location.pathname != '/chat') {
|
||||
const file_entry = `[${file.name}]`
|
||||
if (selected_text) {
|
||||
let old_value = ta.value
|
||||
ta.value = old_value.replace(selected_text, file_entry);
|
||||
ta.selectionEnd = selection_end + ta.value.length - old_value.length;
|
||||
}
|
||||
else {
|
||||
ta.setRangeText(`${file_entry}\n`);
|
||||
}
|
||||
}
|
||||
if (location.pathname != '/chat')
|
||||
if (ta.value)
|
||||
ta.setRangeText(`\n[${file.name}]`);
|
||||
else
|
||||
ta.setRangeText(`[${file.name}]`);
|
||||
}
|
||||
|
||||
autoExpand(ta)
|
||||
|
@ -516,21 +484,22 @@ function handle_files(input, newfiles) {
|
|||
file_upload = document.getElementById('file-upload');
|
||||
|
||||
if (file_upload) {
|
||||
const IMAGE_FORMATS = document.getElementById('IMAGE_FORMATS').value.split(',')
|
||||
|
||||
function process_url_image() {
|
||||
if (file_upload.files)
|
||||
{
|
||||
const filename = file_upload.files[0].name
|
||||
file_upload.previousElementSibling.textContent = filename.substr(0, 50);
|
||||
if (IMAGE_FORMATS.some(s => filename.toLowerCase().endsWith(s)))
|
||||
for (const s of document.getElementById('IMAGE_FORMATS').value.split(','))
|
||||
{
|
||||
if (filename.toLowerCase().endsWith(s)) {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.readAsDataURL(file_upload.files[0]);
|
||||
fileReader.addEventListener("load", function () {
|
||||
document.getElementById('image-preview').setAttribute('src', this.result);
|
||||
document.getElementById('image-preview').classList.remove('d-none');
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof checkForRequired === "function") {
|
||||
|
@ -608,3 +577,25 @@ function handleUploadProgress(e, upload_prog) {
|
|||
percentIndicator.textContent = progressPercent + '%';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (width <= 768) {
|
||||
expandImageModal.addEventListener('show.bs.modal', function () {
|
||||
setTimeout(() => {
|
||||
location.hash = "modal";
|
||||
}, 200);
|
||||
});
|
||||
|
||||
expandImageModal.addEventListener('hide.bs.modal', function () {
|
||||
if(location.hash == "#modal") {
|
||||
history.back();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('hashchange', function () {
|
||||
if(location.hash != "#modal") {
|
||||
const curr_modal = bootstrap.Modal.getInstance(document.getElementsByClassName('show')[0])
|
||||
if (curr_modal) curr_modal.hide()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ function report_postModal(id) {
|
|||
xhr.onload = function() {
|
||||
let data
|
||||
try {data = JSON.parse(xhr.response)}
|
||||
catch(e) {console.log(e)}
|
||||
catch(e) {console.error(e)}
|
||||
success = xhr.status >= 200 && xhr.status < 300;
|
||||
showToast(success, getMessageFromJsonData(success, data));
|
||||
};
|
||||
|
|
|
@ -1,26 +1,40 @@
|
|||
const submitButton = document.getElementById('submit-btn')
|
||||
const save_value = ['post-title', 'post-text', 'post-url', 'sub']
|
||||
for (const id of save_value) {
|
||||
const value = localStorage.getItem(id)
|
||||
if (value)
|
||||
document.getElementById(id).value = value
|
||||
}
|
||||
|
||||
document.getElementById('post-title').value = localStorage.getItem("post-title")
|
||||
document.getElementById('post-text').value = localStorage.getItem("post-text")
|
||||
autoExpand(document.getElementById('post-text'))
|
||||
document.getElementById('post-url').value = localStorage.getItem("post-url")
|
||||
|
||||
const sub_entry = document.getElementById('sub')
|
||||
if (!sub_entry.value) {
|
||||
sub_entry.value = localStorage.getItem("sub")
|
||||
}
|
||||
|
||||
document.getElementById('post-notify').checked = localStorage.getItem("post-notify") == 'true'
|
||||
document.getElementById('post-new').checked = localStorage.getItem("post-new") == 'true'
|
||||
const postnsfw = document.getElementById('post-nsfw')
|
||||
if (postnsfw) {
|
||||
postnsfw.checked = localStorage.getItem("post-nsfw") == 'true'
|
||||
}
|
||||
document.getElementById('post-private').checked = localStorage.getItem("post-private") == 'true'
|
||||
document.getElementById('post-ghost').checked = localStorage.getItem("post-ghost") == 'true'
|
||||
|
||||
markdown(document.getElementById("post-text"));
|
||||
|
||||
const save_checked = ['post-notify', 'post-new', 'post-nsfw', 'post-private', 'post-ghost']
|
||||
for (const key of save_checked) {
|
||||
const value = localStorage.getItem(key)
|
||||
if (value) {
|
||||
const element = document.getElementById(key)
|
||||
if (element) element.checked = (value == 'true')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function savetext() {
|
||||
for (const id of save_value)
|
||||
{
|
||||
const value = document.getElementById(id).value
|
||||
if (value) localStorage.setItem(id, value)
|
||||
}
|
||||
|
||||
for (const id of save_checked) {
|
||||
const element = document.getElementById(id)
|
||||
if (element) {
|
||||
localStorage.setItem(id, element.checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const submitButton = document.getElementById('submit-btn')
|
||||
|
||||
function checkForRequired() {
|
||||
const title = document.getElementById("post-title");
|
||||
const url = document.getElementById("post-url");
|
||||
|
@ -63,25 +77,6 @@ function hide_image() {
|
|||
}
|
||||
}
|
||||
|
||||
const saved_values = ['post-title', 'post-text', 'post-url', 'sub']
|
||||
|
||||
function savetext() {
|
||||
for (const id of saved_values)
|
||||
{
|
||||
const value = document.getElementById(id).value
|
||||
if (value) localStorage.setItem(id, value)
|
||||
}
|
||||
|
||||
localStorage.setItem("post-notify", document.getElementById('post-notify').checked)
|
||||
localStorage.setItem("post-new", document.getElementById('post-new').checked)
|
||||
if (postnsfw) {
|
||||
localStorage.setItem("post-nsfw", document.getElementById('post-nsfw').checked)
|
||||
}
|
||||
localStorage.setItem("post-private", document.getElementById('post-private').checked)
|
||||
localStorage.setItem("post-ghost", document.getElementById('post-ghost').checked)
|
||||
}
|
||||
|
||||
|
||||
function autoSuggestTitle() {
|
||||
|
||||
const urlField = document.getElementById("post-url");
|
||||
|
@ -135,7 +130,7 @@ function checkRepost() {
|
|||
|
||||
xhr.onload=function(){
|
||||
try {data = JSON.parse(xhr.response)}
|
||||
catch(e) {console.log(e)}
|
||||
catch(e) {console.error(e)}
|
||||
|
||||
if (data && data["permalink"]) {
|
||||
const permalinkText = escapeHTML(data["permalink"]);
|
||||
|
@ -180,17 +175,19 @@ function submit(form) {
|
|||
upload_prog.classList.add("d-none")
|
||||
|
||||
if (xhr.status >= 200 && xhr.status < 300) {
|
||||
const post_id = JSON.parse(xhr.response)['post_id'];
|
||||
const res = JSON.parse(xhr.response)
|
||||
const post_id = res['post_id'];
|
||||
|
||||
localStorage.setItem("post-title", "")
|
||||
localStorage.setItem("post-text", "")
|
||||
localStorage.setItem("post-url", "")
|
||||
localStorage.setItem("sub", "")
|
||||
localStorage.setItem("post-notify", true)
|
||||
localStorage.setItem("post-new", false)
|
||||
localStorage.setItem("post-nsfw", false)
|
||||
localStorage.setItem("post-private", false)
|
||||
localStorage.setItem("post-ghost", false)
|
||||
if (res['success']) {
|
||||
for (const id of save_value) {
|
||||
localStorage.setItem(id, "")
|
||||
}
|
||||
|
||||
for (const id of save_checked) {
|
||||
const value = (id == "post-notify")
|
||||
localStorage.setItem(id, value)
|
||||
}
|
||||
}
|
||||
|
||||
location.href = "/post/" + post_id
|
||||
} else {
|
||||
|
|
|
@ -29,8 +29,6 @@ function transferCoins(t, mobile=false) {
|
|||
el.classList.add('d-none');
|
||||
}
|
||||
|
||||
this.disabled = true;
|
||||
|
||||
let amount = parseInt(document.getElementById(mobile ? "coin-transfer-amount-mobile" : "coin-transfer-amount").value);
|
||||
let transferred = amount - Math.ceil(amount*TRANSFER_TAX);
|
||||
let username = document.getElementById('username').innerHTML;
|
||||
|
@ -46,8 +44,6 @@ function transferCoins(t, mobile=false) {
|
|||
document.getElementById("profile-coins-amount").innerText = parseInt(document.getElementById("profile-coins-amount").innerText) + transferred;
|
||||
}
|
||||
);
|
||||
|
||||
setTimeout(_ => this.disabled = false, 2000);
|
||||
}
|
||||
|
||||
function transferBux(t, mobile=false) {
|
||||
|
@ -55,8 +51,6 @@ function transferBux(t, mobile=false) {
|
|||
el.classList.add('d-none');
|
||||
}
|
||||
|
||||
this.disabled = true;
|
||||
|
||||
let amount = parseInt(document.getElementById(mobile ? "bux-transfer-amount-mobile" : "bux-transfer-amount").value);
|
||||
let username = document.getElementById('username').innerHTML
|
||||
|
||||
|
@ -71,8 +65,6 @@ function transferBux(t, mobile=false) {
|
|||
document.getElementById("profile-bux-amount").innerText = parseInt(document.getElementById("profile-bux-amount").innerText) + amount;
|
||||
}
|
||||
);
|
||||
|
||||
setTimeout(_ => this.disabled = false, 2000);
|
||||
}
|
||||
|
||||
function sendMessage(form) {
|
||||
|
|
|
@ -5,7 +5,7 @@ from sqlalchemy.orm import relationship
|
|||
from sqlalchemy.sql.sqltypes import *
|
||||
|
||||
from files.classes import Base
|
||||
from files.helpers.config.const import SITE_NAME
|
||||
from files.helpers.config.const import *
|
||||
from files.helpers.lazy import lazy
|
||||
|
||||
class BadgeDef(Base):
|
||||
|
@ -26,8 +26,8 @@ class BadgeDef(Base):
|
|||
@property
|
||||
@lazy
|
||||
def path(self):
|
||||
if 20 < self.id < 28 or self.id == 222: return f"/i/{SITE_NAME}/badges/{self.id}.webp"
|
||||
return f"/i/badges/{self.id}.webp"
|
||||
if 20 < self.id < 28 or self.id == 222: return SITE_FULL + f"/i/{SITE_NAME}/badges/{self.id}.webp"
|
||||
return SITE_FULL + f"/i/badges/{self.id}.webp"
|
||||
|
||||
class Badge(Base):
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ from sqlalchemy.orm import relationship, scoped_session
|
|||
from sqlalchemy.sql.sqltypes import *
|
||||
|
||||
from files.classes import Base
|
||||
from files.helpers.config.const import SITE_FULL
|
||||
from files.helpers.config.const import *
|
||||
from files.helpers.lazy import lazy
|
||||
|
||||
from .comment import Comment
|
||||
|
|
|
@ -28,6 +28,72 @@ def normalize_urls_runtime(body, v):
|
|||
body = body.replace('https://instagram.com/p/', 'https://imginn.com/p/')
|
||||
return body
|
||||
|
||||
|
||||
def add_options(self, body, v):
|
||||
if isinstance(self, Comment):
|
||||
kind = 'comment'
|
||||
else:
|
||||
kind = 'post'
|
||||
|
||||
if self.options:
|
||||
curr = [x for x in self.options if x.exclusive and x.voted(v)]
|
||||
if curr: curr = f" value={kind}-" + str(curr[0].id)
|
||||
else: curr = ''
|
||||
body += f'<input class="d-none" id="current-{kind}-{self.id}"{curr}>'
|
||||
winner = [x for x in self.options if x.exclusive == 3]
|
||||
|
||||
for o in self.options:
|
||||
option_body = ''
|
||||
|
||||
if o.exclusive > 1:
|
||||
option_body += f'''<div class="custom-control mt-2"><input name="option-{self.id}" autocomplete="off" class="custom-control-input bet" type="radio" id="{o.id}" data-nonce="{g.nonce}" data-onclick="bet_vote(this,'{o.id}','{kind}')"'''
|
||||
if o.voted(v): option_body += " checked "
|
||||
if not (v and v.coins >= POLL_BET_COINS) or self.total_bet_voted(v): option_body += " disabled "
|
||||
|
||||
option_body += f'''><label class="custom-control-label" for="{o.id}">{o.body_html}<span class="presult-{self.id}'''
|
||||
option_body += f'"> - <a href="/votes/{kind}/option/{o.id}"><span id="option-{o.id}">{o.upvotes}</span> bets</a>'
|
||||
if not self.total_bet_voted(v):
|
||||
option_body += f'''<span class="cost"> (cost of entry: {POLL_BET_COINS} coins or marseybux)</span>'''
|
||||
option_body += "</label>"
|
||||
|
||||
if o.exclusive == 3:
|
||||
option_body += " - <b>WINNER!</b>"
|
||||
|
||||
if not winner and v and v.admin_level >= PERMS['POST_BETS_DISTRIBUTE']:
|
||||
option_body += f'''<button class="btn btn-primary distribute" data-areyousure="postToastReload(this,'/distribute/{kind}/{o.id}')" data-nonce="{g.nonce}" data-onclick="areyousure(this)">Declare winner</button>'''
|
||||
option_body += "</div>"
|
||||
else:
|
||||
input_type = 'radio' if o.exclusive else 'checkbox'
|
||||
option_body += f'<div class="custom-control mt-2"><input type="{input_type}" class="custom-control-input" id="{kind}-{o.id}" name="option-{self.id}"'
|
||||
if o.voted(v): option_body += " checked"
|
||||
|
||||
if v:
|
||||
if kind == 'post':
|
||||
sub = self.sub
|
||||
else:
|
||||
sub = self.post.sub
|
||||
|
||||
if sub in {'furry','vampire','racist','femboy'} and not v.house.lower().startswith(sub): option_body += ' disabled '
|
||||
option_body += f''' data-nonce="{g.nonce}" data-onclick="poll_vote_{o.exclusive}('{o.id}', '{self.id}', '{kind}')"'''
|
||||
else:
|
||||
option_body += f''' data-nonce="{g.nonce}" data-onclick="poll_vote_no_v()"'''
|
||||
|
||||
option_body += f'''><label class="custom-control-label" for="{kind}-{o.id}">{o.body_html}<span class="presult-{self.id}'''
|
||||
if not self.total_poll_voted(v): option_body += ' d-none'
|
||||
option_body += f'"> - <a href="/votes/{kind}/option/{o.id}"><span id="score-{kind}-{o.id}">{o.upvotes}</span> votes</a></label></div>'''
|
||||
|
||||
if o.exclusive > 1: s = '##'
|
||||
elif o.exclusive: s = '&&'
|
||||
else: s = '$$'
|
||||
|
||||
if f'{s}{o.body_html}{s}' in body:
|
||||
body = body.replace(f'{s}{o.body_html}{s}', option_body, 1)
|
||||
elif not o.created_utc or o.created_utc < 1677622270:
|
||||
body += option_body
|
||||
|
||||
return body
|
||||
|
||||
|
||||
class Comment(Base):
|
||||
__tablename__ = "comments"
|
||||
|
||||
|
@ -122,12 +188,6 @@ class Comment(Base):
|
|||
def fullname(self):
|
||||
return f"c_{self.id}"
|
||||
|
||||
@lazy
|
||||
def parent(self, db:scoped_session):
|
||||
if not self.parent_submission: return None
|
||||
if self.level == 1: return self.post
|
||||
else: return db.get(Comment, self.parent_comment_id)
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def parent_fullname(self):
|
||||
|
@ -238,6 +298,15 @@ class Comment(Base):
|
|||
|
||||
return data
|
||||
|
||||
@lazy
|
||||
def total_bet_voted(self, v):
|
||||
if "closed" in self.body.lower(): return True
|
||||
if v:
|
||||
for o in self.options:
|
||||
if o.exclusive == 3: return True
|
||||
if o.exclusive == 2 and o.voted(v): return True
|
||||
return False
|
||||
|
||||
@lazy
|
||||
def total_poll_voted(self, v):
|
||||
if v:
|
||||
|
@ -252,37 +321,7 @@ class Comment(Base):
|
|||
|
||||
body = self.body_html or ""
|
||||
|
||||
if self.options:
|
||||
curr = [x for x in self.options if x.exclusive and x.voted(v)]
|
||||
if curr: curr = " value=comment-" + str(curr[0].id)
|
||||
else: curr = ''
|
||||
body += f'<input class="d-none" id="current-comment-{self.id}"{curr}>'
|
||||
|
||||
for o in self.options:
|
||||
input_type = 'radio' if o.exclusive else 'checkbox'
|
||||
option_body = f'<div class="custom-control"><input type="{input_type}" class="custom-control-input" id="comment-{o.id}" name="option-{self.id}"'
|
||||
if o.voted(v): option_body += " checked"
|
||||
|
||||
if v:
|
||||
if self.parent_submission:
|
||||
sub = self.post.sub
|
||||
if sub in {'furry','vampire','racist','femboy'} and not v.house.lower().startswith(sub): option_body += ' disabled '
|
||||
option_body += f''' data-nonce="{g.nonce}" data-onclick="poll_vote_{o.exclusive}('{o.id}', '{self.id}', 'comment')"'''
|
||||
else:
|
||||
option_body += f''' data-nonce="{g.nonce}" data-onclick="poll_vote_no_v()"'''
|
||||
|
||||
option_body += f'''><label class="custom-control-label" for="comment-{o.id}">{o.body_html}<span class="presult-{self.id}'''
|
||||
if not self.total_poll_voted(v): option_body += ' d-none'
|
||||
option_body += f'"> - <a href="/votes/comment/option/{o.id}"><span id="score-comment-{o.id}">{o.upvotes}</span> votes</a></label></div>'''
|
||||
|
||||
if o.exclusive > 1: s = '!!'
|
||||
elif o.exclusive: s = '&&'
|
||||
else: s = '$$'
|
||||
|
||||
if f'{s}{o.body_html}{s}' in body:
|
||||
body = body.replace(f'{s}{o.body_html}{s}', option_body, 1)
|
||||
elif not o.created_utc or o.created_utc < 1677622270:
|
||||
body += option_body
|
||||
body = add_options(self, body, v)
|
||||
|
||||
if body:
|
||||
body = censor_slurs(body, v)
|
||||
|
|
|
@ -3,7 +3,7 @@ from typing import Any, Callable, Optional, Tuple, Union
|
|||
from sqlalchemy import Column, func
|
||||
from sqlalchemy.orm import scoped_session
|
||||
|
||||
from files.helpers.config.const import LEADERBOARD_LIMIT
|
||||
from files.helpers.config.const import *
|
||||
|
||||
from .badges import Badge
|
||||
from .marsey import Marsey
|
||||
|
|
|
@ -22,4 +22,4 @@ class Notification(Base):
|
|||
super().__init__(*args, **kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__name__}(id={self.id})>"
|
||||
return f"<{self.__class__.__name__}(user_id={self.user_id}, comment_id={self.comment_id})>"
|
||||
|
|
|
@ -17,7 +17,7 @@ class SubmissionOption(Base):
|
|||
created_utc = Column(Integer)
|
||||
|
||||
votes = relationship("SubmissionOptionVote")
|
||||
post = relationship("Submission", back_populates="options")
|
||||
parent = relationship("Submission", back_populates="options")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
|
||||
|
@ -36,11 +36,6 @@ class SubmissionOption(Base):
|
|||
if not v: return False
|
||||
return v.id in [x.user_id for x in self.votes]
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def parent(self):
|
||||
return self.post
|
||||
|
||||
|
||||
class SubmissionOptionVote(Base):
|
||||
|
||||
|
@ -72,7 +67,7 @@ class CommentOption(Base):
|
|||
created_utc = Column(Integer)
|
||||
|
||||
votes = relationship("CommentOptionVote")
|
||||
comment = relationship("Comment", back_populates="options")
|
||||
parent = relationship("Comment", back_populates="options")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
|
||||
|
@ -91,11 +86,6 @@ class CommentOption(Base):
|
|||
if not v: return False
|
||||
return v.id in [x.user_id for x in self.votes]
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def parent(self):
|
||||
return self.comment
|
||||
|
||||
class CommentOptionVote(Base):
|
||||
|
||||
__tablename__ = "comment_option_votes"
|
||||
|
|
|
@ -40,7 +40,7 @@ class Sub(Base):
|
|||
@property
|
||||
@lazy
|
||||
def sidebar_url(self):
|
||||
if self.sidebarurl: return SITE_FULL + self.sidebarurl
|
||||
if self.sidebarurl: return self.sidebarurl
|
||||
return f'/i/{SITE_NAME}/sidebar.webp?v=3009'
|
||||
|
||||
@property
|
||||
|
@ -61,7 +61,7 @@ class Sub(Base):
|
|||
@property
|
||||
@lazy
|
||||
def marsey_url(self):
|
||||
if self.marseyurl: return SITE_FULL + self.marseyurl
|
||||
if self.marseyurl: return self.marseyurl
|
||||
return f'/i/{SITE_NAME}/headericon.webp?v=3009'
|
||||
|
||||
@property
|
||||
|
|
|
@ -13,7 +13,7 @@ from files.helpers.lazy import lazy
|
|||
from files.helpers.regex import *
|
||||
from files.helpers.sorting_and_time import make_age_string
|
||||
|
||||
from .comment import normalize_urls_runtime
|
||||
from .comment import normalize_urls_runtime, add_options
|
||||
from .polls import *
|
||||
from .sub import *
|
||||
from .subscriptions import *
|
||||
|
@ -26,6 +26,7 @@ class Submission(Base):
|
|||
edited_utc = Column(Integer, default=0)
|
||||
created_utc = Column(Integer)
|
||||
thumburl = Column(String)
|
||||
posterurl = Column(String)
|
||||
is_banned = Column(Boolean, default=False)
|
||||
bannedfor = Column(String)
|
||||
chuddedfor = Column(String)
|
||||
|
@ -116,7 +117,8 @@ class Submission(Base):
|
|||
if self.sub and self.sub in {'chudrama', 'countryclub', 'masterbaiters'}:
|
||||
output = '-'
|
||||
else:
|
||||
output = title_regex.sub('', self.title.lower())
|
||||
title = self.plaintitle(None).lower()
|
||||
output = title_regex.sub('', title)
|
||||
output = output.split()[:6]
|
||||
output = '-'.join(output)
|
||||
if not output: output = '-'
|
||||
|
@ -162,6 +164,13 @@ class Submission(Base):
|
|||
return f"{SITE_FULL}/i/{SITE_NAME}/site_preview.webp?v=3009"
|
||||
else: return f"{SITE_FULL}/i/default_thumb_link.webp?v=1"
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def poster_url(self):
|
||||
if self.posterurl: return self.posterurl
|
||||
if self.thumburl: return self.thumburl
|
||||
return None
|
||||
|
||||
@lazy
|
||||
def json(self, db:scoped_session):
|
||||
if self.is_banned:
|
||||
|
@ -196,6 +205,7 @@ class Submission(Base):
|
|||
'is_bot': self.is_bot,
|
||||
'thumb_url': self.thumb_url,
|
||||
'domain': self.domain,
|
||||
'sub': self.sub,
|
||||
'url': self.realurl(None),
|
||||
'body': self.body,
|
||||
'body_html': self.body_html,
|
||||
|
@ -280,57 +290,7 @@ class Submission(Base):
|
|||
|
||||
body = self.body_html or ""
|
||||
|
||||
if self.options:
|
||||
curr = [x for x in self.options if x.exclusive and x.voted(v)]
|
||||
if curr: curr = " value=post-" + str(curr[0].id)
|
||||
else: curr = ''
|
||||
body += f'<input class="d-none" id="current-post-{self.id}"{curr}>'
|
||||
winner = [x for x in self.options if x.exclusive == 3]
|
||||
|
||||
for o in self.options:
|
||||
option_body = ''
|
||||
|
||||
if o.exclusive > 1:
|
||||
option_body += f'''<div class="custom-control mt-2"><input name="option-{self.id}" autocomplete="off" class="custom-control-input bet" type="radio" id="{o.id}" data-nonce="{g.nonce}" data-onclick="bet_vote(this,'{o.id}')"'''
|
||||
if o.voted(v): option_body += " checked "
|
||||
if not (v and v.coins >= POLL_BET_COINS) or self.total_bet_voted(v): option_body += " disabled "
|
||||
|
||||
option_body += f'''><label class="custom-control-label" for="{o.id}">{o.body_html}<span class="presult-{self.id}'''
|
||||
option_body += f'"> - <a href="/votes/post/option/{o.id}"><span id="option-{o.id}">{o.upvotes}</span> bets</a>'
|
||||
if not self.total_bet_voted(v):
|
||||
option_body += f'''<span class="cost"> (cost of entry: {POLL_BET_COINS} coins or marseybux)</span>'''
|
||||
option_body += "</label>"
|
||||
|
||||
if o.exclusive == 3:
|
||||
option_body += " - <b>WINNER!</b>"
|
||||
|
||||
if not winner and v and v.admin_level >= PERMS['POST_BETS_DISTRIBUTE']:
|
||||
option_body += f'''<button class="btn btn-primary distribute" data-areyousure="postToastReload(this,'/distribute/{o.id}')" data-nonce="{g.nonce}" data-onclick="areyousure(this)">Declare winner</button>'''
|
||||
option_body += "</div>"
|
||||
else:
|
||||
input_type = 'radio' if o.exclusive else 'checkbox'
|
||||
option_body += f'<div class="custom-control mt-2"><input type="{input_type}" class="custom-control-input" id="post-{o.id}" name="option-{self.id}"'
|
||||
if o.voted(v): option_body += " checked"
|
||||
|
||||
if v:
|
||||
sub = self.sub
|
||||
if sub in {'furry','vampire','racist','femboy'} and not v.house.lower().startswith(sub): option_body += ' disabled '
|
||||
option_body += f''' data-nonce="{g.nonce}" data-onclick="poll_vote_{o.exclusive}('{o.id}', '{self.id}', 'post')"'''
|
||||
else:
|
||||
option_body += f''' data-nonce="{g.nonce}" data-onclick="poll_vote_no_v()"'''
|
||||
|
||||
option_body += f'''><label class="custom-control-label" for="post-{o.id}">{o.body_html}<span class="presult-{self.id}'''
|
||||
if not self.total_poll_voted(v): option_body += ' d-none'
|
||||
option_body += f'"> - <a href="/votes/post/option/{o.id}"><span id="score-post-{o.id}">{o.upvotes}</span> votes</a></label></div>'''
|
||||
|
||||
if o.exclusive > 1: s = '!!'
|
||||
elif o.exclusive: s = '&&'
|
||||
else: s = '$$'
|
||||
|
||||
if f'{s}{o.body_html}{s}' in body:
|
||||
body = body.replace(f'{s}{o.body_html}{s}', option_body, 1)
|
||||
elif not o.created_utc or o.created_utc < 1677622270:
|
||||
body += option_body
|
||||
body = add_options(self, body, v)
|
||||
|
||||
body = censor_slurs(body, v)
|
||||
body = normalize_urls_runtime(body, v)
|
||||
|
|
|
@ -37,7 +37,7 @@ from .subscriptions import *
|
|||
from .userblock import *
|
||||
|
||||
if SITE == 'devrama.net':
|
||||
DEFAULT_ADMIN_LEVEL = 4
|
||||
DEFAULT_ADMIN_LEVEL = 3
|
||||
DEFAULT_COINS = 100000000
|
||||
DEFAULT_MARSEYBUX = 100000000
|
||||
else:
|
||||
|
@ -228,7 +228,6 @@ class User(Base):
|
|||
elif currency == 'combined':
|
||||
if in_db.marseybux >= amount:
|
||||
subtracted_mbux = amount
|
||||
print(subtracted_mbux, flush=True)
|
||||
subtracted_coins = 0
|
||||
else:
|
||||
subtracted_mbux = in_db.marseybux
|
||||
|
@ -418,6 +417,11 @@ class User(Base):
|
|||
g.db.add(new_badge)
|
||||
g.db.flush()
|
||||
|
||||
if time.time() - self.created_utc > 365 * 86400 * 2 and not self.has_badge(237):
|
||||
new_badge = Badge(badge_id=237, user_id=self.id)
|
||||
g.db.add(new_badge)
|
||||
g.db.flush()
|
||||
|
||||
return False
|
||||
|
||||
@property
|
||||
|
@ -789,7 +793,7 @@ class User(Base):
|
|||
@property
|
||||
@lazy
|
||||
def banner_url(self):
|
||||
if FEATURES['USERS_PROFILE_BANNER'] and self.bannerurl:
|
||||
if FEATURES['USERS_PROFILE_BANNER'] and self.bannerurl and self.can_see_my_shit:
|
||||
return self.bannerurl
|
||||
return f"/i/{SITE_NAME}/site_preview.webp?v=3009"
|
||||
|
||||
|
@ -800,7 +804,7 @@ class User(Base):
|
|||
return f"{SITE_FULL}/e/chudsey.webp"
|
||||
if self.rainbow:
|
||||
return f"{SITE_FULL}/e/marseysalutepride.webp"
|
||||
if self.profileurl:
|
||||
if self.profileurl and self.can_see_my_shit:
|
||||
if self.profileurl.startswith('/'): return SITE_FULL + self.profileurl
|
||||
return self.profileurl
|
||||
return f"{SITE_FULL}/i/default-profile-pic.webp?v=1008"
|
||||
|
@ -1023,7 +1027,6 @@ class User(Base):
|
|||
return False
|
||||
if other.sub and not cls.can_see(user, other.subr):
|
||||
return False
|
||||
|
||||
else:
|
||||
if other.parent_submission:
|
||||
return cls.can_see(user, other.post)
|
||||
|
@ -1035,7 +1038,7 @@ class User(Base):
|
|||
if other.top_comment.author_id == user.id: return True
|
||||
return user.admin_level >= PERMS['VIEW_MODMAIL']
|
||||
if other.sentto != user.id:
|
||||
return False
|
||||
return user.admin_level >= PERMS['BLACKJACK_NOTIFICATIONS']
|
||||
elif isinstance(other, Sub):
|
||||
if other.name == 'chudrama': return bool(user) and user.can_see_chudrama
|
||||
if other.name in {'countryclub','splash_mountain'}: return bool(user) and user.can_see_countryclub
|
||||
|
@ -1203,3 +1206,9 @@ class User(Base):
|
|||
@lazy
|
||||
def can_toggle_event_music(self):
|
||||
return SITE_NAME != 'rDrama' or self.has_badge(91)
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def can_see_my_shit(self):
|
||||
v = g.v
|
||||
return not self.shadowbanned or (v and (v.id == self.id or v.can_see_shadowbanned))
|
||||
|
|
|
@ -51,7 +51,7 @@ def execute_snappy(post:Submission, v:User):
|
|||
|
||||
if v.id == CARP_ID:
|
||||
if random.random() < 0.02: body = "i love you carp"
|
||||
elif random.random() < 0.02: body = "![](/images/16614707883108485.webp)"
|
||||
elif random.random() < 0.02: body = "https://i.rdrama.net/images/16614707883108485.webp"
|
||||
else: body = ":#marseyfuckoffcarp:"
|
||||
elif v.id == LAWLZ_ID:
|
||||
if random.random() < 0.5: body = "wow, this lawlzpost sucks!"
|
||||
|
@ -433,6 +433,8 @@ def execute_antispam_comment_check(body:str, v:User):
|
|||
def execute_under_siege(v:User, target:Optional[Union[Submission, Comment]], body, type:str) -> bool:
|
||||
if not get_setting("under_siege"): return True
|
||||
|
||||
if v.post_count or v.comment_count: return True
|
||||
|
||||
if type in ('flag', 'message'):
|
||||
threshold = 86400
|
||||
else:
|
||||
|
@ -497,7 +499,7 @@ def process_poll_options(v:User, target:Union[Submission, Comment]):
|
|||
|
||||
patterns = [(poll_regex, 0), (choice_regex, 1)]
|
||||
|
||||
if isinstance(target, Submission) and v and v.admin_level >= PERMS['POST_BETS']:
|
||||
if v.admin_level >= PERMS['POST_BETS']:
|
||||
patterns.append((bet_regex, 2))
|
||||
|
||||
option_count = 0
|
||||
|
@ -509,7 +511,7 @@ def process_poll_options(v:User, target:Union[Submission, Comment]):
|
|||
if option_count > POLL_MAX_OPTIONS:
|
||||
abort(400, f"Max number of poll options is {POLL_MAX_OPTIONS}")
|
||||
|
||||
body = i.group(1)
|
||||
body = i.group(2)
|
||||
|
||||
if len(body) > 500:
|
||||
abort(400, f"Poll option body too long! (Max 500 characters)")
|
||||
|
|
|
@ -134,7 +134,8 @@ def NOTIFY_USERS(text, v, oldtext=None, ghost=False):
|
|||
if word in text:
|
||||
notify_users.add(id)
|
||||
|
||||
names = set(m.group(2) for m in mention_regex.finditer(text))
|
||||
names = set(m.group(1) for m in mention_regex.finditer(text))
|
||||
|
||||
user_ids = get_users(names, ids_only=True, graceful=True)
|
||||
notify_users.update(user_ids)
|
||||
|
||||
|
@ -149,31 +150,31 @@ def NOTIFY_USERS(text, v, oldtext=None, ghost=False):
|
|||
cost = 0
|
||||
|
||||
for i in group_mention_regex.finditer(text):
|
||||
if oldtext and i.group(2) in oldtext:
|
||||
if oldtext and i.group(1) in oldtext:
|
||||
continue
|
||||
|
||||
if i.group(2) == 'everyone' and not v.shadowbanned:
|
||||
if i.group(1) == 'everyone' and not v.shadowbanned:
|
||||
cost = g.db.query(User).count() * 5
|
||||
if cost > v.coins:
|
||||
abort(403, f"You need {cost} coins for this!")
|
||||
abort(403, f"You need {cost} coins to mention these ping groups!")
|
||||
g.db.query(User).update({ User.coins: User.coins + 5 })
|
||||
v.charge_account('coins', cost)
|
||||
return 'everyone'
|
||||
else:
|
||||
group = g.db.get(Group, i.group(2))
|
||||
group = g.db.get(Group, i.group(1))
|
||||
if not group: continue
|
||||
|
||||
members = group.member_ids - notify_users - v.all_twoway_blocks
|
||||
|
||||
notify_users.update(members)
|
||||
|
||||
if ghost or v.id not in members:
|
||||
if ghost or v.id not in group.member_ids:
|
||||
if group.name == 'biofoids': mul = 10
|
||||
else: mul = 5
|
||||
|
||||
cost += len(members) * mul
|
||||
if cost > v.coins:
|
||||
abort(403, f"You need {cost} coins for this!")
|
||||
abort(403, f"You need {cost} coins to mention these ping groups!")
|
||||
|
||||
g.db.query(User).filter(User.id.in_(members)).update({ User.coins: User.coins + mul })
|
||||
|
||||
|
@ -200,6 +201,8 @@ def push_notif(uids, title, body, url_or_comment):
|
|||
if len(body) > PUSH_NOTIF_LIMIT:
|
||||
body = body[:PUSH_NOTIF_LIMIT] + "..."
|
||||
|
||||
body = censor_slurs(body, None)
|
||||
|
||||
subscriptions = g.db.query(PushSubscription.subscription_json).filter(PushSubscription.user_id.in_(uids)).all()
|
||||
subscriptions = [x[0] for x in subscriptions]
|
||||
g.db.flush()
|
||||
|
|
|
@ -5,7 +5,7 @@ from collections import defaultdict
|
|||
import gevent
|
||||
import gevent_inotifyx as inotify
|
||||
|
||||
from files.helpers.config.const import IS_FISTMAS
|
||||
from files.helpers.config.const import *
|
||||
|
||||
ASSET_DIR = 'files/assets'
|
||||
ASSET_SUBDIRS = ['/css', '/js', '/js/vendor']
|
||||
|
|
|
@ -4,7 +4,7 @@ from flask import g
|
|||
|
||||
from files.classes.user import User
|
||||
from files.helpers.alerts import send_repeatable_notification
|
||||
from files.helpers.config.const import bots, patron, SITE_NAME
|
||||
from files.helpers.config.const import *
|
||||
|
||||
def award_timers(v, bot=False):
|
||||
now = time.time()
|
||||
|
@ -67,7 +67,13 @@ def award_timers(v, bot=False):
|
|||
badge = v.has_badge(167)
|
||||
if v.bite and v.bite < now:
|
||||
v.bite = None
|
||||
notify_if_not_bot("Your vampire status has ended!")
|
||||
|
||||
notif_text = "Your vampire status has ended."
|
||||
if v.old_house:
|
||||
house = v.old_house.replace(' Founder', '')
|
||||
notif_text += f" You're now back in House {house}!"
|
||||
notify_if_not_bot(notif_text)
|
||||
|
||||
v.house = v.old_house
|
||||
v.old_house = ''
|
||||
badge = v.has_badge(168)
|
||||
|
|
|
@ -3,7 +3,7 @@ from typing import List, Optional, Union
|
|||
|
||||
import requests
|
||||
|
||||
from files.helpers.config.const import CF_HEADERS, CF_ZONE, DEFAULT_CONFIG_VALUE
|
||||
from files.helpers.config.const import *
|
||||
|
||||
CLOUDFLARE_API_URL = "https://api.cloudflare.com/client/v4"
|
||||
CLOUDFLARE_REQUEST_TIMEOUT_SECS = 5
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from copy import deepcopy
|
||||
|
||||
from files.helpers.config.const import FEATURES, SITE_NAME, patron, IS_FISTMAS, IS_HOMOWEEN
|
||||
from files.helpers.config.const import *
|
||||
|
||||
AWARDS = {
|
||||
"fallback": {
|
||||
|
|
|
@ -198,21 +198,21 @@ if SITE_NAME == 'rDrama':
|
|||
SLURS.update(RDRAMA_SLURS)
|
||||
|
||||
BOOSTED_SITES = {
|
||||
#All sites with .win TLD
|
||||
#All sites with the word "forum" in the domain
|
||||
#All sites with the word "chan" in the domain
|
||||
|
||||
#youtube-like
|
||||
'bitchute.com',
|
||||
'goyimtv.tv',
|
||||
'odysee.com',
|
||||
|
||||
#4chan-like
|
||||
'4chan.org',
|
||||
'boards.4channel.org',
|
||||
'boards.4chan.org',
|
||||
'archive.4plebs.org',
|
||||
'lolcow.farm',
|
||||
'8kun.top',
|
||||
'soyjak.party',
|
||||
'crystal.cafe',
|
||||
'choachan.cafe',
|
||||
|
||||
#forums
|
||||
'kiwifarms.net',
|
||||
|
@ -290,7 +290,6 @@ if SITE_NAME == 'rDrama':
|
|||
'wolfballs.com',
|
||||
'dojo.press',
|
||||
'livefilter.com',
|
||||
'mainchan.com',
|
||||
'lesswrong.com',
|
||||
'forum.porpl.net',
|
||||
|
||||
|
@ -313,7 +312,6 @@ if SITE_NAME == 'rDrama':
|
|||
'metafilter.com',
|
||||
'sqwok.im',
|
||||
'thelayoff.com',
|
||||
'stackexchange.com',
|
||||
'stackoverflow.com',
|
||||
'serverfault.com',
|
||||
'superuser.com',
|
||||
|
@ -332,6 +330,8 @@ if SITE_NAME == 'rDrama':
|
|||
'programming',
|
||||
'slackernews',
|
||||
'chudrama',
|
||||
'wallstreetbets',
|
||||
'lit',
|
||||
}
|
||||
|
||||
REDDIT_NOTIFS_SITE.add('marsey')
|
||||
|
@ -381,7 +381,7 @@ PROFANITIES = {
|
|||
slur_single_words = "|".join([slur.lower() for slur in SLURS.keys()])
|
||||
profanity_single_words = "|".join([profanity.lower() for profanity in PROFANITIES.keys()])
|
||||
|
||||
LONGPOST_REPLIES = ('Wow, you must be a JP fan.', 'This is one of the worst posts I have EVER seen. Delete it.', "No, don't reply like this, please do another wall of unhinged rant please.", '# 😴😴😴', "Ma'am we've been over this before. You need to stop.", "I've known more coherent downies.", "Your pulitzer's in the mail", "That's great and all, but I asked for my burger without cheese.", 'That degree finally paying off', "That's nice sweaty. Why don't you have a seat in the time out corner with Pizzashill until you calm down, then you can have your Capri Sun.", "All them words won't bring your pa back.", "You had a chance to not be completely worthless, but it looks like you threw it away. At least you're consistent.", 'Some people are able to display their intelligence by going on at length on a subject and never actually saying anything. This ability is most common in trades such as politics, public relations, and law. You have impressed me by being able to best them all, while still coming off as an absolute idiot.', "You can type 10,000 characters and you decided that these were the one's that you wanted.", 'Have you owned the libs yet?', "I don't know what you said, because I've seen another human naked.", 'Impressive. Normally people with such severe developmental disabilities struggle to write much more than a sentence or two. He really has exceded our expectations for the writing portion. Sadly the coherency of his writing, along with his abilities in the social skills and reading portions, are far behind his peers with similar disabilities.', "This is a really long way of saying you don't fuck.", "Sorry ma'am, looks like his delusions have gotten worse. We'll have to admit him.", 'If only you could put that energy into your relationships', 'Posts like this is why I do Heroine.', 'still unemployed then?', 'K', 'look im gunna have 2 ask u 2 keep ur giant dumps in the toilet not in my replys 😷😷😷', "Mommy is soooo proud of you, sweaty. Let's put this sperg out up on the fridge with all your other failures.", "Good job bobby, here's a star", "That was a mistake. You're about to find out the hard way why.", 'You sat down and wrote all this shit. You could have done so many other things with your life. What happened to your life that made you decide writing novels of bullshit here was the best option?', "I don't have enough spoons to read this shit", "All those words won't bring daddy back.", 'OUT!', "Damn, you're really mad over this, but thanks for the effort you put into typing that all out! Sadly I won't read it all.", "Jesse what the fuck are you talking about??", "▼you're fucking bananas if you think I'm reading all that, take my downvote and shut up idiot", "Are you feeling okay bud?", ':#marseywoah:', 'At no point in your rambling, incoherent post were you even close to anything that could be considered a rational thought. Everyone on this site is now dumber for having read it. May God have mercy on your soul.', 'https://rdrama.net/videos/1671169024815045.mp4', '![](/images/16766675896248007.webp)')
|
||||
LONGPOST_REPLIES = ('Wow, you must be a JP fan.', 'This is one of the worst posts I have EVER seen. Delete it.', "No, don't reply like this, please do another wall of unhinged rant please.", '# 😴😴😴', "Ma'am we've been over this before. You need to stop.", "I've known more coherent downies.", "Your pulitzer's in the mail", "That's great and all, but I asked for my burger without cheese.", 'That degree finally paying off', "That's nice sweaty. Why don't you have a seat in the time out corner with Pizzashill until you calm down, then you can have your Capri Sun.", "All them words won't bring your pa back.", "You had a chance to not be completely worthless, but it looks like you threw it away. At least you're consistent.", 'Some people are able to display their intelligence by going on at length on a subject and never actually saying anything. This ability is most common in trades such as politics, public relations, and law. You have impressed me by being able to best them all, while still coming off as an absolute idiot.', "You can type 10,000 characters and you decided that these were the one's that you wanted.", 'Have you owned the libs yet?', "I don't know what you said, because I've seen another human naked.", 'Impressive. Normally people with such severe developmental disabilities struggle to write much more than a sentence or two. He really has exceded our expectations for the writing portion. Sadly the coherency of his writing, along with his abilities in the social skills and reading portions, are far behind his peers with similar disabilities.', "This is a really long way of saying you don't fuck.", "Sorry ma'am, looks like his delusions have gotten worse. We'll have to admit him.", 'If only you could put that energy into your relationships', 'Posts like this is why I do Heroine.', 'still unemployed then?', 'K', 'look im gunna have 2 ask u 2 keep ur giant dumps in the toilet not in my replys 😷😷😷', "Mommy is soooo proud of you, sweaty. Let's put this sperg out up on the fridge with all your other failures.", "Good job bobby, here's a star", "That was a mistake. You're about to find out the hard way why.", 'You sat down and wrote all this shit. You could have done so many other things with your life. What happened to your life that made you decide writing novels of bullshit here was the best option?', "I don't have enough spoons to read this shit", "All those words won't bring daddy back.", 'OUT!', "Damn, you're really mad over this, but thanks for the effort you put into typing that all out! Sadly I won't read it all.", "Jesse what the fuck are you talking about??", "▼you're fucking bananas if you think I'm reading all that, take my downvote and shut up idiot", "Are you feeling okay bud?", ':#marseywoah:', 'At no point in your rambling, incoherent post were you even close to anything that could be considered a rational thought. Everyone on this site is now dumber for having read it. May God have mercy on your soul.', 'https://rdrama.net/videos/1671169024815045.mp4', 'https://i.rdrama.net/images/16766675896248007.webp')
|
||||
|
||||
AGENDAPOSTER_PHRASE = 'trans lives matter'
|
||||
|
||||
|
@ -486,21 +486,20 @@ PERMS = { # Minimum admin_level to perform action.
|
|||
|
||||
'MODERATE_PENDING_SUBMITTED_ASSETS': 4,
|
||||
'UPDATE_ASSETS': 4,
|
||||
'PROGSTACK': 4,
|
||||
'UNDO_AWARD_PINS': 4,
|
||||
'DELETE_MEDIA': 4,
|
||||
|
||||
'PROGSTACK': 5,
|
||||
'UNDO_AWARD_PINS': 5,
|
||||
'USER_BLACKLIST': 5,
|
||||
'POST_EDITING': 5,
|
||||
'VIEW_PATRONS': 5,
|
||||
'BLACKJACK_NOTIFICATIONS': 5,
|
||||
'IGNORE_BADGE_BLACKLIST': 5,
|
||||
'enable_dm_images': 5,
|
||||
'SEE_GHOST_VOTES': 5,
|
||||
|
||||
'DELETE_MEDIA': 6,
|
||||
|
||||
'USER_BLACKLIST': 7,
|
||||
'POST_EDITING': 7,
|
||||
'VIEW_PATRONS': 7,
|
||||
'BLACKJACK_NOTIFICATIONS': 7,
|
||||
'IGNORE_BADGE_BLACKLIST': 7,
|
||||
'VIEW_DM_IMAGES': 7,
|
||||
'SEE_GHOST_VOTES': 7,
|
||||
|
||||
'MODS_EVERY_HOLE': 8,
|
||||
'MODS_EVERY_HOLE': 6,
|
||||
'MODS_EVERY_GROUP': 6,
|
||||
}
|
||||
|
||||
FEATURES = {
|
||||
|
@ -625,12 +624,12 @@ TRUESCORE_GHOST_MINIMUM = 0
|
|||
TRUESCORE_DONATE_MINIMUM = 10
|
||||
TRUESCORE_MASTERBAITERS_MINIMUM = 100
|
||||
TRUESCORE_CLUB_MINIMUM = 1000
|
||||
TRUESCORE_CHUDRAMA_MINIMUM = 1488
|
||||
TRUESCORE_CHUDRAMA_MINIMUM = 10
|
||||
|
||||
LOGGEDIN_ACTIVE_TIME = 15 * 60
|
||||
PFP_DEFAULT_MARSEY = True
|
||||
NEW_USER_HAT_AGE = 0 # seconds of age to show new-user forced hat
|
||||
NOTIFICATION_SPAM_AGE_THRESHOLD = 0.5 * 86400
|
||||
NOTIFICATION_SPAM_AGE_THRESHOLD = 0
|
||||
COMMENT_SPAM_LENGTH_THRESHOLD = 0
|
||||
UNDER_SIEGE_AGE_THRESHOLD = 10 * 60
|
||||
|
||||
|
@ -711,9 +710,10 @@ BADGE_BLACKLIST = { # only grantable by admins higher than PERMS['IGNORE_BADGE_B
|
|||
}
|
||||
|
||||
NOTIFIED_USERS = {}
|
||||
DONT_SHADOWBAN = {}
|
||||
|
||||
if SITE == 'rdrama.net':
|
||||
NOTIFICATION_SPAM_AGE_THRESHOLD = 0.5 * 86400
|
||||
|
||||
TELEGRAM_ID = "rdramanet"
|
||||
DEFAULT_TIME_FILTER = "day"
|
||||
|
||||
|
@ -793,13 +793,11 @@ if SITE == 'rdrama.net':
|
|||
|
||||
ANTISPAM_BYPASS_IDS = {1703, 13427}
|
||||
|
||||
DONT_SHADOWBAN = {253,3161,11163}
|
||||
|
||||
GIFT_NOTIF_ID = CARP_ID
|
||||
|
||||
POLL_THREAD = 79285
|
||||
|
||||
WELCOME_MSG = "Hi there! It's me, your soon-to-be favorite rDrama user @carpathianflorist here to give you a brief rundown on some of the sick features we have here. You'll probably want to start by following me, though. So go ahead and click my name and then smash that Follow button. This is actually really important, so go on. Hurry.\n\nThanks!\n\nNext up: If you're a member of the media, similarly just shoot me a DM and I'll set about verifying you and then we can take care of your sad journalism stuff.\n\n**FOR EVERYONE ELSE**\n\n Begin by navigating to [the settings page](/settings/profile) (we'll be prettying this up so it's less convoluted soon, don't worry) and getting some basic customization done.\n\n### Themes\n\nDefinitely change your theme right away, the default one (Midnight) is pretty enough, but why not use something *exotic* like Win98, or *flashy* like Tron? Even Coffee is super tasteful and way more fun than the default. More themes to come when we get around to it!\n\n### Avatar/pfp\n\nYou'll want to set this pretty soon. Set the banner too while you're at it. Your profile is important!\n\n### Flairs\n\nSince you're already on the settings page, you may as well set a flair, too. As with your username, you can - obviously - choose the color of this, either with a hex value or just from the preset colors. And also like your username, you can change this at any time. Paypigs can even further relive the glory days of 90s-00s internet and set obnoxious signatures.\n\n### PROFILE ANTHEMS\n\nSpeaking of profiles, hey, remember MySpace? Do you miss autoplaying music assaulting your ears every time you visited a friend's page? Yeah, we brought that back. Enter a YouTube URL, wait a few seconds for it to process, and then BAM! you've got a profile anthem which people cannot mute. Unless they spend 20,000 dramacoin in the shop for a mute button. Which you can then remove from your profile by spending 40,000 dramacoin on an unmuteable anthem. Get fucked poors!\n\n### Dramacoin?\n\nDramacoin is basically our take on the karma system. Except unlike the karma system, it's not gay and boring and stupid and useless. Dramacoin can be spent at [Marsey's Dramacoin Emporium](/shop) on upgrades to your user experience (many more coming than what's already listed there), and best of all on tremendously annoying awards to fuck with your fellow dramautists. We're always adding more, so check back regularly in case you happen to miss one of the announcement posts.\n\nLike karma, dramacoin is obtained by getting upvotes on your threads and comments. *Unlike* karma, it's also obtained by getting downvotes on your threads and comments. Downvotes don't really do anything here - they pay the same amount of dramacoin and they increase thread/comment ranking just the same as an upvote. You just use them to express petty disapproval and hopefully start a fight. Because all votes are visible here. To hell with your anonymity.\n\nDramacoin can also be traded amongst users from their profiles. Note that there is a 3% transaction fee.\n\n### Badges\n\nRemember all those neat little metallic icons you saw on my profile when you were following me? If not, scroll back up and go have a look. And doublecheck to make sure you pressed the Follow button. Anyway, those are badges. You earn them by doing a variety of things. Some of them even offer benefits, like discounts at the shop. A [complete list of badges and their requirements can be found here](/badges), though I add more pretty regularly, so keep an eye on the [changelog](/h/changelog).\n\n### Other stuff\n\nWe're always adding new features, and we take a fun-first approach to development. If you have a suggestion for something that would be fun, funny, annoying - or best of all, some combination of all three - definitely make a thread about it. Or just DM me if you're shy. Weirdo. Anyway there's also the [leaderboards](/leaderboard), boring stuff like two-factor authentication you can toggle on somewhere in the settings page (psycho), the ability to save posts and comments, more than a thousand emojis already (most of which are rDrama originals), and on and on and on and on. This is just the basics, mostly to help you get acquainted with some of the things you can do here to make it more easy on the eyes, customizable, and enjoyable. If you don't enjoy it, just go away! We're not changing things to suit you! Get out of here loser! And no, you can't delete your account :na:\n\nI love you.<br>*xoxo Carp* 💋"
|
||||
WELCOME_MSG = "Hi there! It's me, your soon-to-be favorite rDrama user @carpathianflorist here to give you a brief rundown on some of the sick features we have here. You'll probably want to start by following me, though. So go ahead and click my name and then smash that Follow button. This is actually really important, so go on. Hurry.\n\nThanks!\n\nNext up: If you're a member of the media, similarly just shoot me a DM and I'll set about verifying you and then we can take care of your sad journalism stuff.\n\n**FOR EVERYONE ELSE**\n\n Begin by navigating to [the settings page](/settings/profile) (we'll be prettying this up so it's less convoluted soon, don't worry) and getting some basic customization done.\n\n### Themes\n\nDefinitely change your theme right away, the default one (Midnight) is pretty enough, but why not use something *exotic* like Win98, or *flashy* like Tron? Even Coffee is super tasteful and way more fun than the default. More themes to come when we get around to it!\n\n### Avatar/pfp\n\nYou'll want to set this pretty soon. Set the banner too while you're at it. Your profile is important!\n\n### Flairs\n\nSince you're already on the settings page, you may as well set a flair, too. As with your username, you can - obviously - choose the color of this, either with a hex value or just from the preset colors. And also like your username, you can change this at any time. Paypigs can even further relive the glory days of 90s-00s internet and set obnoxious signatures.\n\n### PROFILE ANTHEMS\n\nSpeaking of profiles, hey, remember MySpace? Do you miss autoplaying music assaulting your ears every time you visited a friend's page? Yeah, we brought that back. Enter a YouTube URL, wait a few seconds for it to process, and then BAM! you've got a profile anthem which people cannot mute. Unless they spend 20,000 dramacoin in the shop for a mute button. Which you can then remove from your profile by spending 40,000 dramacoin on an unmuteable anthem. Get fucked poors!\n\n### Dramacoin?\n\nDramacoin is basically our take on the karma system. Except unlike the karma system, it's not gay and boring and stupid and useless. Dramacoin can be spent at [Marsey's Dramacoin Emporium](/shop/awards) on upgrades to your user experience (many more coming than what's already listed there), and best of all on tremendously annoying awards to fuck with your fellow dramautists. We're always adding more, so check back regularly in case you happen to miss one of the announcement posts.\n\nLike karma, dramacoin is obtained by getting upvotes on your threads and comments. *Unlike* karma, it's also obtained by getting downvotes on your threads and comments. Downvotes don't really do anything here - they pay the same amount of dramacoin and they increase thread/comment ranking just the same as an upvote. You just use them to express petty disapproval and hopefully start a fight. Because all votes are visible here. To hell with your anonymity.\n\nDramacoin can also be traded amongst users from their profiles. Note that there is a 3% transaction fee.\n\n### Badges\n\nRemember all those neat little metallic icons you saw on my profile when you were following me? If not, scroll back up and go have a look. And doublecheck to make sure you pressed the Follow button. Anyway, those are badges. You earn them by doing a variety of things. Some of them even offer benefits, like discounts at the shop. A [complete list of badges and their requirements can be found here](/badges), though I add more pretty regularly, so keep an eye on the [changelog](/h/changelog).\n\n### Other stuff\n\nWe're always adding new features, and we take a fun-first approach to development. If you have a suggestion for something that would be fun, funny, annoying - or best of all, some combination of all three - definitely make a thread about it. Or just DM me if you're shy. Weirdo. Anyway there's also the [leaderboards](/leaderboard), boring stuff like two-factor authentication you can toggle on somewhere in the settings page (psycho), the ability to save posts and comments, more than a thousand emojis already (most of which are rDrama originals), and on and on and on and on. This is just the basics, mostly to help you get acquainted with some of the things you can do here to make it more easy on the eyes, customizable, and enjoyable. If you don't enjoy it, just go away! We're not changing things to suit you! Get out of here loser! And no, you can't delete your account :na:\n\nI love you.<br>*xoxo Carp* 💋"
|
||||
|
||||
REDDIT_NOTIFS_USERS = {
|
||||
'idio3': IDIO_ID,
|
||||
|
@ -811,8 +809,10 @@ if SITE == 'rdrama.net':
|
|||
'justcool393': JUSTCOOL_ID
|
||||
}
|
||||
|
||||
POST_RATELIMIT = '5/hour;10/day'
|
||||
POST_RATELIMIT = '10/day'
|
||||
elif SITE == 'watchpeopledie.tv':
|
||||
NOTIFICATION_SPAM_AGE_THRESHOLD = 0.5 * 86400
|
||||
|
||||
EMAIL = "wpd@watchpeopledie.tv"
|
||||
TELEGRAM_ID = "wpdtv"
|
||||
DEFAULT_TIME_FILTER = "day"
|
||||
|
@ -894,6 +894,10 @@ elif SITE == 'watchpeopledie.tv':
|
|||
}
|
||||
elif SITE == 'devrama.net':
|
||||
AEVANN_ID = 7
|
||||
FEATURES['ASSET_SUBMISSIONS'] = True
|
||||
FEATURES['PRONOUNS'] = True
|
||||
FEATURES['HOUSES'] = True
|
||||
FEATURES['USERS_PERMANENT_WORD_FILTERS'] = True
|
||||
else: # localhost or testing environment implied
|
||||
FEATURES['ASSET_SUBMISSIONS'] = True
|
||||
FEATURES['PRONOUNS'] = True
|
||||
|
@ -980,6 +984,7 @@ approved_embed_hosts = {
|
|||
'tumblr.com', # concerningly broad.
|
||||
'ytimg.com',
|
||||
'yt3.ggpht.com',
|
||||
'bitchute.com',
|
||||
|
||||
### Third-Party Resources (For e.g. Profile Customization)
|
||||
# TODO: Any reasonable way to proxy these instead?
|
||||
|
@ -1057,8 +1062,6 @@ if not IS_LOCALHOST and SECRET_KEY == DEFAULT_CONFIG_VALUE:
|
|||
from warnings import warn
|
||||
warn("Secret key is the default value! Please change it to a secure random number. Thanks <3", RuntimeWarning)
|
||||
|
||||
SHOW_MORE = '<p><button class="showmore">SHOW MORE</button></p></div><div class="d-none">'
|
||||
|
||||
if AEVANN_ID:
|
||||
GLOBAL = environ.get("GLOBAL", "").strip()
|
||||
else:
|
||||
|
|
|
@ -96,6 +96,11 @@ MODACTION_TYPES = {
|
|||
"icon": 'fa-images',
|
||||
"color": 'bg-muted'
|
||||
},
|
||||
'disable_automatic_DDOS_mitigation': {
|
||||
"str": 'disabled automatic DDOS mitigation',
|
||||
"icon": 'fa-shield-virus',
|
||||
"color": 'bg-danger'
|
||||
},
|
||||
'distinguish_comment': {
|
||||
"str": 'distinguished {self.target_link}',
|
||||
"icon": 'fa-crown',
|
||||
|
@ -161,6 +166,11 @@ MODACTION_TYPES = {
|
|||
"icon": 'fa-images',
|
||||
"color": 'bg-success',
|
||||
},
|
||||
'enable_automatic_DDOS_mitigation': {
|
||||
"str": 'enabled automatic DDOS mitigation',
|
||||
"icon": 'fa-shield-virus',
|
||||
"color": 'bg-success',
|
||||
},
|
||||
'flair_post': {
|
||||
"str": 'set a flair on {self.target_link}',
|
||||
"icon": 'fa-tag',
|
||||
|
@ -393,6 +403,8 @@ MODACTION_TYPES = {
|
|||
},
|
||||
}
|
||||
|
||||
MODACTION_TYPES = dict(sorted(MODACTION_TYPES.items()))
|
||||
|
||||
MODACTION_PRIVILEGED_TYPES = {'shadowban', 'unshadowban',
|
||||
'mod_mute_user', 'mod_unmute_user',
|
||||
'link_accounts', 'delink_accounts',
|
||||
|
@ -408,4 +420,6 @@ MODACTION_TYPES__FILTERED = deepcopy({t:v for t,v in MODACTION_TYPES.items()
|
|||
AEVANN_MODACTION_TYPES = {'ban_user','unban_user',
|
||||
'shadowban','unshadowban',
|
||||
'progstack_post','progstack_comment',
|
||||
'unprogstack_post', 'unprogstack_comment'}
|
||||
'unprogstack_post', 'unprogstack_comment',
|
||||
'delete_media',
|
||||
'enable_automatic_DDOS_mitigation', 'disable_automatic_DDOS_mitigation'}
|
||||
|
|
|
@ -115,3 +115,5 @@ SUBACTION_TYPES = {
|
|||
"color": 'bg-success'
|
||||
},
|
||||
}
|
||||
|
||||
SUBACTION_TYPES = dict(sorted(SUBACTION_TYPES.items()))
|
||||
|
|
|
@ -3,7 +3,7 @@ from os import path
|
|||
from sqlalchemy.orm import scoped_session
|
||||
|
||||
from files.classes import Marsey
|
||||
from files.helpers.config.const import IS_FISTMAS, SITE_NAME
|
||||
from files.helpers.config.const import *
|
||||
|
||||
marseys_const = []
|
||||
marseys_const2 = []
|
||||
|
|
|
@ -29,6 +29,7 @@ from files.cli import app, db_session, g
|
|||
@click.option('--every-1mo', is_flag=True, help='Call every 1 month.')
|
||||
def cron(every_5m, every_1h, every_1d, every_1mo):
|
||||
g.db = db_session()
|
||||
g.v = None
|
||||
|
||||
if every_5m:
|
||||
if FEATURES['GAMBLING']:
|
||||
|
|
|
@ -5,7 +5,7 @@ from sqlalchemy import and_, any_, or_
|
|||
from sqlalchemy.orm import joinedload, selectinload, Query
|
||||
|
||||
from files.classes import Comment, CommentVote, Hat, Sub, Submission, User, UserBlock, Vote
|
||||
from files.helpers.config.const import AUTOJANNY_ID
|
||||
from files.helpers.config.const import *
|
||||
from files.__main__ import cache
|
||||
|
||||
def sanitize_username(username:str) -> str:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from files.helpers.config.const import LOG_DIRECTORY
|
||||
from files.helpers.config.const import *
|
||||
|
||||
def log_file(log_str:str, log_filename="rdrama.log"):
|
||||
'''
|
||||
|
|
|
@ -2,7 +2,7 @@ import requests
|
|||
import time
|
||||
|
||||
from files.helpers.security import *
|
||||
from files.helpers.config.const import EMAIL
|
||||
from files.helpers.config.const import *
|
||||
|
||||
from urllib.parse import quote
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ def process_files(files, v, body):
|
|||
name = f'/images/{time.time()}'.replace('.','') + '.webp'
|
||||
file.save(name)
|
||||
url = process_image(name, v)
|
||||
body = body.replace(f'[{file.filename}]', f"![]({url})", 1)
|
||||
body = body.replace(f'[{file.filename}]', url, 1)
|
||||
elif file.content_type.startswith('video/'):
|
||||
body = body.replace(f'[{file.filename}]', process_video(file, v), 1)
|
||||
elif file.content_type.startswith('audio/'):
|
||||
|
@ -257,9 +257,8 @@ def process_image(filename:str, v, resize=0, trim=False, uploader_id:Optional[in
|
|||
)
|
||||
db.add(media)
|
||||
|
||||
if SITE == 'rdrama.net': return f'https://i.{SITE}{filename}'
|
||||
return filename
|
||||
|
||||
if IS_LOCALHOST: return f'![]({filename})'
|
||||
return f'https://i.{SITE}{filename}'
|
||||
|
||||
|
||||
def process_dm_images(v, user, body):
|
||||
|
|
|
@ -20,6 +20,7 @@ OWO_EXCLUDE_PATTERNS = [
|
|||
sanitize.url_re, # bare links
|
||||
re.compile(r':[!#@a-z0-9_\-]+:', flags=re.I|re.A), # emoji
|
||||
help_re.mention_regex, # mentions
|
||||
help_re.group_mention_regex, #ping group mentions
|
||||
help_re.poll_regex, # polls
|
||||
help_re.choice_regex,
|
||||
help_re.command_regex, # markup commands
|
||||
|
|
|
@ -7,11 +7,11 @@ from .config.const import *
|
|||
|
||||
valid_username_chars = 'a-zA-Z0-9_\-'
|
||||
valid_username_regex = re.compile("^[a-zA-Z0-9_\-]{3,25}$", flags=re.A)
|
||||
mention_regex = re.compile('(^|\s|>)@([a-zA-Z0-9_\-]{1,30})(?![^<]*<\/(code|pre|a)>)', flags=re.A)
|
||||
|
||||
group_mention_regex = re.compile('(^|\s|>)!([a-z0-9_\-]{3,25})(?![^<]*<\/(code|pre|a)>)', flags=re.A)
|
||||
mention_regex = re.compile('@([a-zA-Z0-9_\-]{1,30})(?!([^<]*<\/(code|pre|a)>|[^`]*`))', flags=re.A)
|
||||
group_mention_regex = re.compile('!([a-z0-9_\-]{3,25})(?!([^<]*<\/(code|pre|a)>|[^`]*`))', flags=re.A|re.I)
|
||||
|
||||
everyone_regex = re.compile('(^|\s|>)!(everyone)(?![^<]*<\/(code|pre|a)>)', flags=re.A)
|
||||
everyone_regex = re.compile('(^|\s|>)!(everyone)(?!([^<]*<\/(code|pre|a)>|[^`]*`))', flags=re.A)
|
||||
|
||||
valid_password_regex = re.compile("^.{8,100}$", flags=re.A)
|
||||
|
||||
|
@ -25,15 +25,15 @@ tags_regex = re.compile("[a-z0-9: ]{1,200}", flags=re.A)
|
|||
hat_regex = re.compile("[a-zA-Z0-9\-() ,_]{1,50}", flags=re.A)
|
||||
description_regex = re.compile("[^<>&\n\t]{1,300}", flags=re.A)
|
||||
|
||||
badge_name_regex = re.compile("[A-Za-z0-9 ]+", flags=re.A)
|
||||
badge_name_regex = re.compile(r"[^\/.]+", flags=re.A)
|
||||
|
||||
valid_sub_regex = re.compile("^[a-zA-Z0-9_\-]{3,25}$", flags=re.A)
|
||||
|
||||
query_regex = re.compile("(\w+):(\S+)", flags=re.A)
|
||||
|
||||
poll_regex = re.compile("\s*\$\$([^\$\n]+)\$\$\s*(?!([^<]*<\/(code|pre|a)>|[^`]*`))", flags=re.A)
|
||||
bet_regex = re.compile("\s*!!([^\$\n]+)!!\s*(?!([^<]*<\/(code|pre|a)>|[^`]*`))", flags=re.A)
|
||||
choice_regex = re.compile("\s*&&([^\$\n]+)&&\s*(?!([^<]*<\/(code|pre|a)>|[^`]*`))", flags=re.A)
|
||||
poll_regex = re.compile("(^|\n)\$\$([^\$\n]+)\$\$\s*?(?!([^<]*<\/(code|pre|a)>|[^`]*`))", flags=re.A)
|
||||
bet_regex = re.compile("(^|\n)##([^\!\n]+)##\s*?(?!([^<]*<\/(code|pre|a)>|[^`]*`))", flags=re.A)
|
||||
choice_regex = re.compile("(^|\n)&&([^\&\n]+)&&\s*?(?!([^<]*<\/(code|pre|a)>|[^`]*`))", flags=re.A)
|
||||
|
||||
html_comment_regex = re.compile("<!--.*-->", flags=re.A)
|
||||
|
||||
|
@ -43,16 +43,16 @@ controversial_regex = re.compile('["> ](https:\/\/old\.reddit\.com/r/[a-zA-Z0-9_
|
|||
|
||||
fishylinks_regex = re.compile("(https?:\/\/)?[\w\-.#&/=\?@%;+,:]{2,10}\.[\w\-.#&/=\?@%;+,:]{2,250}", flags=re.A)
|
||||
|
||||
spoiler_regex = re.compile('\|\|(.+?)\|\|(?![^<]*<\/(code|pre|a)>)', flags=re.A)
|
||||
reddit_regex = re.compile('(^|\s|<p>)\/?((r|u)\/(\w|-){3,25})(?![^<]*<\/(code|pre|a)>)', flags=re.A)
|
||||
sub_regex = re.compile('(^|\s|<p>)\/?(h\/(\w|-){3,25})(?![^<]*<\/(code|pre|a)>)', flags=re.A)
|
||||
spoiler_regex = re.compile('\|\|(.+?)\|\|(?!([^<]*<\/(code|pre|a)>|[^`]*`))', flags=re.A)
|
||||
reddit_regex = re.compile('(^|\s|<p>)\/?((r|u)\/(\w|-){3,25})(?!([^<]*<\/(code|pre|a)>|[^`]*`))', flags=re.A)
|
||||
sub_regex = re.compile('(^|\s|<p>)\/?(h\/(\w|-){3,25})(?!([^<]*<\/(code|pre|a)>|[^`]*`))', flags=re.A)
|
||||
|
||||
strikethrough_regex = re.compile('(^|\s|>)~{1,2}([^~]+)~{1,2}(?![^<]*<\/(code|pre|a)>)', flags=re.A)
|
||||
strikethrough_regex = re.compile('(^|\s|>)~{1,2}([^~]+)~{1,2}(?!([^<]*<\/(code|pre|a)>|[^`]*`))', flags=re.A)
|
||||
|
||||
mute_regex = re.compile("\/mute @?([a-z0-9_\-]{3,30}) ([0-9]+)", flags=re.A|re.I)
|
||||
|
||||
emoji_regex = re.compile(f"<p>\s*(:[!#@]{{0,3}}[{valid_username_chars}]+:\s*)+<\/p>", flags=re.A)
|
||||
emoji_regex2 = re.compile(f'(?<!"):([!#@{valid_username_chars}]{{1,36}}?):(?![^<]*<\/(code|pre|a)>)', flags=re.A)
|
||||
emoji_regex2 = re.compile(f'(?<!"):([!#@{valid_username_chars}]{{1,36}}?):(?!([^<]*<\/(code|pre|a)>|[^`]*`))', flags=re.A)
|
||||
emoji_regex3 = re.compile(f'(?<!"):([!@{valid_username_chars}]{{1,35}}?):', flags=re.A)
|
||||
|
||||
snappy_url_regex = re.compile('<a href="(https?:\/\/.+?)".*?>(.+?)<\/a>', flags=re.A)
|
||||
|
|