Merge branch 'master' into feature-multiple-sub-banners

pull/59/head
Snakes 2022-12-11 18:42:33 -05:00
commit dd167471d3
Signed by: Snakes
GPG Key ID: E745A82778055C7E
128 changed files with 817 additions and 683 deletions

View File

@ -1,9 +0,0 @@
# Netscape HTTP Cookie File
# This file is generated by youtube-dl. Do not edit.
.youtube.com TRUE / TRUE 1670617632 GPS 1
.youtube.com TRUE / TRUE 1686122687 VISITOR_INFO1_LIVE Z0qo6y1x43g
.youtube.com TRUE / TRUE 0 YSC X7P6d8R9T4I
.youtube.com TRUE / TRUE 1686122708 __Secure-3PAPISID V15R47kUEcecf2e6/Anq8BG6Hc8s3_B4aU
.youtube.com TRUE / TRUE 1686122708 __Secure-3PSID Rgi3mkz3GttQzOzz5BydFq1VJYJxYYsNX7tSsaWVvdV5OjMrGX4VQesgyjqm7MEb_U9QbA.
.youtube.com TRUE / TRUE 1702106955 __Secure-3PSIDCC AIKkIs2XJmFoUqmOzZTlvJO6WXpOpP8OwPdrLG7E2hC2DR6IFy_vz0PraZdTy36zFrYJBGuY

View File

@ -1,4 +1,206 @@
@charset "UTF-8";
.fa-align-left:before{content:"\f036"}
.fa-long-arrow-left:before{content:"\f177"}
.fa-arrow-right:before{content:"\f061"}
.fa-sign-out:before{content:"\f08b"}
.fa-long-arrow-right:before{content:"\f178"}
.fa-arrows-v:before{content:"\f07d"}
.fa-award:before{content:"\f559"}
.fa-badge:before{content:"\f335"}
.fa-badge-check:before{content:"\f336"}
.fa-ban:before{content:"\f05e"}
.fa-bars:before{content:"\f0c9"}
.fa-bell:before{content:"\f0f3"}
.fa-bold:before{content:"\f032"}
.fa-book:before{content:"\f02d"}
.fa-book-open:before{content:"\f518"}
.fa-book-dead:before{content:"\f6b7"}
.fa-broom:before{content:"\f51a"}
.fa-bug:before{content:"\f188"}
.fa-bullhorn:before{content:"\f0a1"}
.fa-calendar:before{content:"\f133"}
.fa-calendar-day:before{content:"\f783"}
.fa-calendar-alt:before{content:"\f073"}
.fa-calendar-week:before{content:"\f784"}
.fa-campfire:before{content:"\f6ba"}
.fa-candy-cane:before{content:"\f786"}
.fa-car-tilt:before{content:"\f5e5"}
.fa-cat:before{content:"\f6be"}
.fa-check:before{content:"\f00c"}
.fa-circle:before{content:"\f111"}
.fa-check-circle:before{content:"\f058"}
.fa-arrow-alt-circle-down:before{content:"\f358"}
.fa-exclamation-circle:before{content:"\f06a"}
.fa-info-circle:before{content:"\f05a"}
.fa-radiation-alt:before{content:"\f7ba"}
.fa-arrow-alt-circle-up:before{content:"\f35b"}
.fa-user-circle:before{content:"\f2bd"}
.fa-times-circle:before{content:"\f057"}
.fa-clipboard:before{content:"\f328"}
.fa-clipboard-check:before{content:"\f46c"}
.fa-clock:before{content:"\f017"}
.fa-history:before{content:"\f1da"}
.fa-code:before{content:"\f121"}
.fa-comment:before{content:"\f075"}
.fa-comment-dots:before{content:"\f4ad"}
.fa-comments:before{content:"\f086"}
.fa-copy:before{content:"\f0c5"}
.fa-crown:before{content:"\f521"}
.fa-dice-six:before{content:"\f526"}
.fa-dollar-sign:before{content:"\24"}
.fa-arrow-alt-down:before{content:"\f354"}
.fa-compress-alt:before{content:"\f422"}
.fa-ellipsis-h:before{content:"\f141"}
.fa-envelope:before{content:"\f0e0"}
.fa-envelope-open-text:before{content:"\f658"}
.fa-eye:before{content:"\f06e"}
.fa-eye-evil:before{content:"\f6db"}
.fa-eye-slash:before{content:"\f070"}
.fa-angry:before{content:"\f556"}
.fa-frown:before{content:"\f119"}
.fa-grin-beam-sweat:before{content:"\f583"}
.fa-laugh-squint:before{content:"\f59b"}
.fa-smile-beam:before{content:"\f5b8"}
.fa-feather-alt:before{content:"\f56b"}
.fa-file-signature:before{content:"\f573"}
.fa-filter:before{content:"\f0b0"}
.fa-fire:before{content:"\f06d"}
.fa-fireplace:before{content:"\f79a"}
.fa-fish:before{content:"\f578"}
.fa-flag:before{content:"\f024"}
.fa-flag-usa:before{content:"\f74d"}
.fa-save:before{content:"\f0c7"}
.fa-gavel:before{content:"\f0e3"}
.fa-cog:before{content:"\f013"}
.fa-ghost:before{content:"\f6e2"}
.fa-gift:before{content:"\f06b"}
.fa-gingerbread-man:before{content:"\f79d"}
.fa-globe:before{content:"\f0ac"}
.fa-home-alt:before{content:"\f015"}
.fa-id-badge:before{content:"\f2c1"}
.fa-id-card:before{content:"\f2c2"}
.fa-image:before{content:"\f03e"}
.fa-infinity:before{content:"\f534"}
.fa-italic:before{content:"\f033"}
.fa-knife-kitchen:before{content:"\f6f5"}
.fa-lights-holiday:before{content:"\f7b2"}
.fa-link:before{content:"\f0c1"}
.fa-link-slash:before{content:"\f127"}
.fa-lock:before{content:"\f023"}
.fa-lock-alt:before{content:"\f30d"}
.fa-search:before{content:"\f002"}
.fa-cloudflare:before{content:"\e07d"}
.fa-comment-alt-smile:before{content:"\f4aa"}
.fa-microphone-stand:before{content:"\f8cb"}
.fa-palette:before{content:"\f53f"}
.fa-edit:before{content:"\f044"}
.fa-pizza-slice:before{content:"\f818"}
.fa-poop:before{content:"\f619"}
.fa-quote-right:before{content:"\f10e"}
.fa-reply:before{content:"\f3e5"}
.fa-robot:before{content:"\f544"}
.fa-sack-dollar:before{content:"\f81d"}
.fa-scroll-old:before{content:"\f70f"}
.fa-seedling:before{content:"\f4d8"}
.fa-shield:before{content:"\f132"}
.fa-random:before{content:"\f074"}
.fa-smoke:before{content:"\f760"}
.fa-snooze:before{content:"\f880"}
.fa-snowflake:before{content:"\f2dc"}
.fa-sparkles:before{content:"\f890"}
.fa-ticket:before{content:"\f145"}
.fa-cards:before{content:"\e3ed"}
.fa-spider:before{content:"\f717"}
.fa-square:before{content:"\f0c8"}
.fa-stocking:before{content:"\f7d5"}
.fa-store:before{content:"\f54e"}
.fa-columns:before{content:"\f0db"}
.fa-thumbtack:before{content:"\f08d"}
.fa-train:before{content:"\f238"}
.fa-trash-alt:before{content:"\f2ed"}
.fa-exclamation-triangle:before{content:"\f071"}
.fa-trophy:before{content:"\f091"}
.fa-arrow-alt-up:before{content:"\f357"}
.fa-expand-alt:before{content:"\f424"}
.fa-external-link-alt:before{content:"\f35d"}
.fa-user:before{content:"\f007"}
.fa-user-crown:before{content:"\f6a4"}
.fa-user-cog:before{content:"\f4fe"}
.fa-user-friends:before{content:"\f500"}
.fa-user-lock:before{content:"\f502"}
.fa-user-minus:before{content:"\f503"}
.fa-user-plus:before{content:"\f234"}
.fa-user-slash:before{content:"\f506"}
.fa-user-tag:before{content:"\f507"}
.fa-user-times:before{content:"\f235"}
.fa-users:before{content:"\f0c0"}
.fa-volume:before{content:"\f6a8"}
.fa-volume-mute:before{content:"\f6a9"}
.fa-times:before{content:"\f00d"}
.fa-mobile:before{content:"\f3ce"}
.fa-discord:before{content:"\f392"}
.fa-github:before{content:"\f09b"}
.fa-twitter:before{content:"\f099"}
.fa-git-alt:before{content:"\f841"}
.fa-head-side:before{content:"\f6e9"}
.fa-crab:before{content:"\e3ff"}
.fa-socks:before{content:"\f696"}
.fa-arrow-up:before{content:"\f062"}
.fa-tag:before{content:"\f02b"}
.fa-messages:before{content:"\f4b6"}
.fa-user-secret:before{content:"\f21b"}
.fa-gas-pump-slash:before{content:"\f5f4"}
.fa-gas-pump:before{content:"\f52f"}
.fa-hammer-crash:before{content:"\e414"}
.fa-music:before{content:"\f001"}
.fa-arrow-rotate-right:before{content:"\f01e"}
.fa-columns-3:before{content:"\e361"}
.fa-bahai:before{content:"\f666"}
.fa-party-horn:before{content:"\e31b"}
.fa-pinata:before{content:"\e3c3"}
.fa-file:before{content:"\f15b"}
.fa-box-open:before{content:"\f49e"}
.fa-eyes:before{content:"\e367"}
.fa-hexagon:before{content:"\f312"}
.fa-arrow-right-arrow-left:before{content:"\f0ec"}
.fa-coins:before{content:"\f51e"}
.fa-bell-slash:before{content:"\f1f6"}
.fa-chart-network:before{content:"\f78a"}
.fa-square-share-nodes:before{content:"\f1e1"}
.fa-sidebar:before{content:"\e24e"}
.fa-panorama:before{content:"\e209"}
.fa-external-link:before{content:"\f08e"}
.fa-circle-info:before{content:"\f05a"}
.fa-comment-question:before{content:"\e14b"}
.fa-sitemap:before{content:"\f0e8"}
.fa-grid:before{content:"\e195"}
.fa-x:before{content:"\58"}
.fa-paw-simple:before{content:"\f701"}
.fa-bat:before{content:"\f6b5"}
.fa-star-of-david:before{content:"\f69a"}
.fa-hat-cowboy:before{content:"\f8c0"}
.fa-cloud-rainbow:before{content:"\f73e"}
.fa-telegram:before{content:"\f2c6"}
.fa-css3-alt:before{content:"\f38b"}
.fa-landscape:before{content:"\e1b5"}
.fa-user-ninja:before{content:"\f504"}
.fa-trees:before{content:"\f724"}
.fa-flashlight:before{content:"\f8b8"}
.fa-candy-corn:before{content:"\f6bd"}
.fa-shirt:before{content:"\f553"}
.fa-bone:before{content:"\f5d7"}
.fa-jack-o-lantern:before{content:"\f30e"}
.fa-cloud-bolt:before{content:"\f76c"}
.fa-biohazard:before{content:"\f780"}
.fa-syringe:before{content:"\f48e"}
.fa-spider-web:before{content:"\f719"}
.fa-coffin-cross:before{content:"\e051"}
.fa-face-sleeping:before{content:"\e38d"}
.fa-block-question:before{content:"\e3dd"}
.fa-image-slash:before{content:"\e1b7"}
.fa-play:before{content:"\f04b"}
button {
background: none;
border: none;
@ -4290,8 +4492,8 @@ pre .com, code .com {
background-color: var(--gray-600);
}
.custom-gutters, .user-gutters {
padding-left: 2px;
padding-right: 2px;
padding-left: 0;
padding-right: 0;
}
.navbar.bg-primary {
background-color: var(--dark) !important;
@ -4894,7 +5096,7 @@ code {
.noshadow {
box-shadow: none !important;
}
[role="button"], :not(textarea)[onclick] {
[role="button"], :not(textarea)[onclick], th {
cursor: pointer !important;
}
@ -5696,6 +5898,25 @@ g {
border-radius:.35rem;
}
.video-play {
position:absolute;
bottom:33%;
right:38%;
font-size:14px;
color:white;
background-color:var(--primary);
padding: 5px 6px 4px 7px;
border-radius:.35rem;
pointer-events: none;
}
@media (max-width: 768px) {
.video-play {
bottom:31%;
right:36%;
}
}
/* ------- Font Awesome ------- */
@font-face{
font-family:"Font Awesome 6 Pro";
@ -5876,206 +6097,6 @@ g {
.fa-stack-1x{line-height:inherit}
.fa-stack-2x{font-size:2em}
.fa-align-left:before{content:"\f036"}
.fa-long-arrow-left:before{content:"\f177"}
.fa-arrow-right:before{content:"\f061"}
.fa-sign-out:before{content:"\f08b"}
.fa-long-arrow-right:before{content:"\f178"}
.fa-arrows-v:before{content:"\f07d"}
.fa-award:before{content:"\f559"}
.fa-badge:before{content:"\f335"}
.fa-badge-check:before{content:"\f336"}
.fa-ban:before{content:"\f05e"}
.fa-bars:before{content:"\f0c9"}
.fa-bell:before{content:"\f0f3"}
.fa-bold:before{content:"\f032"}
.fa-book:before{content:"\f02d"}
.fa-book-open:before{content:"\f518"}
.fa-book-dead:before{content:"\f6b7"}
.fa-broom:before{content:"\f51a"}
.fa-bug:before{content:"\f188"}
.fa-bullhorn:before{content:"\f0a1"}
.fa-calendar:before{content:"\f133"}
.fa-calendar-day:before{content:"\f783"}
.fa-calendar-alt:before{content:"\f073"}
.fa-calendar-week:before{content:"\f784"}
.fa-campfire:before{content:"\f6ba"}
.fa-candy-cane:before{content:"\f786"}
.fa-car-tilt:before{content:"\f5e5"}
.fa-cat:before{content:"\f6be"}
.fa-check:before{content:"\f00c"}
.fa-circle:before{content:"\f111"}
.fa-check-circle:before{content:"\f058"}
.fa-arrow-alt-circle-down:before{content:"\f358"}
.fa-exclamation-circle:before{content:"\f06a"}
.fa-info-circle:before{content:"\f05a"}
.fa-radiation-alt:before{content:"\f7ba"}
.fa-arrow-alt-circle-up:before{content:"\f35b"}
.fa-user-circle:before{content:"\f2bd"}
.fa-times-circle:before{content:"\f057"}
.fa-clipboard:before{content:"\f328"}
.fa-clipboard-check:before{content:"\f46c"}
.fa-clock:before{content:"\f017"}
.fa-history:before{content:"\f1da"}
.fa-code:before{content:"\f121"}
.fa-comment:before{content:"\f075"}
.fa-comment-dots:before{content:"\f4ad"}
.fa-comments:before{content:"\f086"}
.fa-copy:before{content:"\f0c5"}
.fa-crown:before{content:"\f521"}
.fa-dice-six:before{content:"\f526"}
.fa-dollar-sign:before{content:"\24"}
.fa-arrow-alt-down:before{content:"\f354"}
.fa-compress-alt:before{content:"\f422"}
.fa-ellipsis-h:before{content:"\f141"}
.fa-envelope:before{content:"\f0e0"}
.fa-envelope-open-text:before{content:"\f658"}
.fa-eye:before{content:"\f06e"}
.fa-eye-evil:before{content:"\f6db"}
.fa-eye-slash:before{content:"\f070"}
.fa-angry:before{content:"\f556"}
.fa-frown:before{content:"\f119"}
.fa-grin-beam-sweat:before{content:"\f583"}
.fa-laugh-squint:before{content:"\f59b"}
.fa-smile-beam:before{content:"\f5b8"}
.fa-feather-alt:before{content:"\f56b"}
.fa-file-signature:before{content:"\f573"}
.fa-filter:before{content:"\f0b0"}
.fa-fire:before{content:"\f06d"}
.fa-fireplace:before{content:"\f79a"}
.fa-fish:before{content:"\f578"}
.fa-flag:before{content:"\f024"}
.fa-flag-usa:before{content:"\f74d"}
.fa-save:before{content:"\f0c7"}
.fa-gavel:before{content:"\f0e3"}
.fa-cog:before{content:"\f013"}
.fa-ghost:before{content:"\f6e2"}
.fa-gift:before{content:"\f06b"}
.fa-gingerbread-man:before{content:"\f79d"}
.fa-globe:before{content:"\f0ac"}
.fa-home-alt:before{content:"\f015"}
.fa-id-badge:before{content:"\f2c1"}
.fa-id-card:before{content:"\f2c2"}
.fa-image:before{content:"\f03e"}
.fa-infinity:before{content:"\f534"}
.fa-italic:before{content:"\f033"}
.fa-knife-kitchen:before{content:"\f6f5"}
.fa-lights-holiday:before{content:"\f7b2"}
.fa-link:before{content:"\f0c1"}
.fa-link-slash:before{content:"\f127"}
.fa-lock:before{content:"\f023"}
.fa-lock-alt:before{content:"\f30d"}
.fa-search:before{content:"\f002"}
.fa-cloudflare:before{content:"\e07d"}
.fa-comment-alt-smile:before{content:"\f4aa"}
.fa-microphone-stand:before{content:"\f8cb"}
.fa-palette:before{content:"\f53f"}
.fa-edit:before{content:"\f044"}
.fa-pizza-slice:before{content:"\f818"}
.fa-poop:before{content:"\f619"}
.fa-quote-right:before{content:"\f10e"}
.fa-reply:before{content:"\f3e5"}
.fa-robot:before{content:"\f544"}
.fa-sack-dollar:before{content:"\f81d"}
.fa-scroll-old:before{content:"\f70f"}
.fa-seedling:before{content:"\f4d8"}
.fa-shield:before{content:"\f132"}
.fa-random:before{content:"\f074"}
.fa-smoke:before{content:"\f760"}
.fa-snooze:before{content:"\f880"}
.fa-snowflake:before{content:"\f2dc"}
.fa-sparkles:before{content:"\f890"}
.fa-ticket:before{content:"\f145"}
.fa-cards:before{content:"\e3ed"}
.fa-spider:before{content:"\f717"}
.fa-square:before{content:"\f0c8"}
.fa-stocking:before{content:"\f7d5"}
.fa-store:before{content:"\f54e"}
.fa-columns:before{content:"\f0db"}
.fa-thumbtack:before{content:"\f08d"}
.fa-train:before{content:"\f238"}
.fa-trash-alt:before{content:"\f2ed"}
.fa-exclamation-triangle:before{content:"\f071"}
.fa-trophy:before{content:"\f091"}
.fa-arrow-alt-up:before{content:"\f357"}
.fa-expand-alt:before{content:"\f424"}
.fa-external-link-alt:before{content:"\f35d"}
.fa-user:before{content:"\f007"}
.fa-user-crown:before{content:"\f6a4"}
.fa-user-cog:before{content:"\f4fe"}
.fa-user-friends:before{content:"\f500"}
.fa-user-lock:before{content:"\f502"}
.fa-user-minus:before{content:"\f503"}
.fa-user-plus:before{content:"\f234"}
.fa-user-slash:before{content:"\f506"}
.fa-user-tag:before{content:"\f507"}
.fa-user-times:before{content:"\f235"}
.fa-users:before{content:"\f0c0"}
.fa-volume:before{content:"\f6a8"}
.fa-volume-mute:before{content:"\f6a9"}
.fa-times:before{content:"\f00d"}
.fa-mobile:before{content:"\f3ce"}
.fa-discord:before{content:"\f392"}
.fa-github:before{content:"\f09b"}
.fa-twitter:before{content:"\f099"}
.fa-git-alt:before{content:"\f841"}
.fa-head-side:before{content:"\f6e9"}
.fa-crab:before{content:"\e3ff"}
.fa-socks:before{content:"\f696"}
.fa-arrow-up:before{content:"\f062"}
.fa-tag:before{content:"\f02b"}
.fa-messages:before{content:"\f4b6"}
.fa-user-secret:before{content:"\f21b"}
.fa-gas-pump-slash:before{content:"\f5f4"}
.fa-gas-pump:before{content:"\f52f"}
.fa-hammer-crash:before{content:"\e414"}
.fa-music:before{content:"\f001"}
.fa-arrow-rotate-right:before{content:"\f01e"}
.fa-columns-3:before{content:"\e361"}
.fa-bahai:before{content:"\f666"}
.fa-party-horn:before{content:"\e31b"}
.fa-pinata:before{content:"\e3c3"}
.fa-file:before{content:"\f15b"}
.fa-box-open:before{content:"\f49e"}
.fa-eyes:before{content:"\e367"}
.fa-hexagon:before{content:"\f312"}
.fa-arrow-right-arrow-left:before{content:"\f0ec"}
.fa-coins:before{content:"\f51e"}
.fa-bell-slash:before{content:"\f1f6"}
.fa-chart-network:before{content:"\f78a"}
.fa-square-share-nodes:before{content:"\f1e1"}
.fa-sidebar:before{content:"\e24e"}
.fa-panorama:before{content:"\e209"}
.fa-external-link:before{content:"\f08e"}
.fa-circle-info:before{content:"\f05a"}
.fa-comment-question:before{content:"\e14b"}
.fa-sitemap:before{content:"\f0e8"}
.fa-grid:before{content:"\e195"}
.fa-x:before{content:"\58"}
.fa-paw-simple:before{content:"\f701"}
.fa-bat:before{content:"\f6b5"}
.fa-star-of-david:before{content:"\f69a"}
.fa-hat-cowboy:before{content:"\f8c0"}
.fa-cloud-rainbow:before{content:"\f73e"}
.fa-telegram:before{content:"\f2c6"}
.fa-css3-alt:before{content:"\f38b"}
.fa-landscape:before{content:"\e1b5"}
.fa-user-ninja:before{content:"\f504"}
.fa-trees:before{content:"\f724"}
.fa-flashlight:before{content:"\f8b8"}
.fa-candy-corn:before{content:"\f6bd"}
.fa-shirt:before{content:"\f553"}
.fa-bone:before{content:"\f5d7"}
.fa-jack-o-lantern:before{content:"\f30e"}
.fa-cloud-bolt:before{content:"\f76c"}
.fa-biohazard:before{content:"\f780"}
.fa-syringe:before{content:"\f48e"}
.fa-spider-web:before{content:"\f719"}
.fa-coffin-cross:before{content:"\e051"}
.fa-face-sleeping:before{content:"\e38d"}
.fa-block-question:before{content:"\e3dd"}
.fa-image-slash:before{content:"\e1b7"}
.pronouns {
font-size: 9px;
margin-left: 0.25rem;
@ -6407,7 +6428,7 @@ div.markdown {
}
:root {
--signature-max-height: 250px;
--signature-max-height: 300px;
}
.user-signature {
@ -6415,10 +6436,6 @@ div.markdown {
overflow: clip;
}
.user-signature video {
height: var(--signature-max-height);
}
.award-name {
font-weight: bold;
font-size: 14px;
@ -6444,3 +6461,31 @@ div.markdown {
.sub-banner-update-section .sub-settings-subsection {
margin-bottom: 1em;
}
.resizable {
resize:both;
display:inline-block;
overflow: auto;
scrollbar-width: none;
-ms-overflow-style: none;
}
.resizable::-webkit-scrollbar {
background: transparent;
}
.resizable > video {
height:100%!important;
max-height:100%!important;
margin:0!important;
}
.bigger {
height:50vh;
}
.user-signature video {
max-height: min(var(--signature-max-height),50vh) !important;
}
.comment-text lite-youtube, #post-text lite-youtube {
max-width: 500px;
margin-top: 5px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 710 B

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 472 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -233,12 +233,6 @@ function expandDesktopImage(url) {
bootstrap.Modal.getOrCreateInstance(document.getElementById('expandImageModal')).show();
};
document.addEventListener("click", function(e){
const element = e.target
if (element instanceof HTMLImageElement && element.alt.startsWith('![]('))
expandDesktopImage()
});
function bs_trigger(e) {
let tooltipTriggerList = [].slice.call(e.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.map(function(element){
@ -342,7 +336,7 @@ function areyousure(t) {
else
t.innerHTML = t.innerHTML.replace(t.textContent, 'Are you sure?')
t.setAttribute("onclick", t.dataset.click2);
t.setAttribute("onclick", t.dataset.click);
if (t.dataset.dismiss)
t.setAttribute("data-bs-dismiss", t.dataset.dismiss);
@ -404,3 +398,51 @@ function sendFormXHRSwitch(e) {
}
)
}
let sortAscending = {};
function sort_table(t) {
const n = Array.prototype.indexOf.call(t.parentElement.children, t);
const table = this.event.target.parentElement.parentElement.parentElement
const rows = table.rows;
let items = [];
for (let i = 1; i < rows.length; i++) {
const ele = rows[i];
let x = rows[i].getElementsByTagName("TD")[n];
if (!('sortKey' in x.dataset)) {
x = x.getElementsByTagName('a')[0] || x;
}
let attr;
if ('sortKey' in x.dataset) {
attr = x.dataset.sortKey;
} else if ('time' in x.dataset) {
attr = parseInt(x.dataset.time);
} else {
attr = x.innerText
if (/^[\d-,]+$/.test(x.innerHTML)) {
attr = parseInt(attr.replace(/,/g, ''))
}
}
items.push({ele, attr});
}
if (sortAscending[n]) {
items.sort((a, b) => a.attr > b.attr ? 1 : -1);
sortAscending[n] = false;
} else {
items.sort((a, b) => a.attr < b.attr ? 1 : -1);
sortAscending[n] = true;
}
for (let i = items.length - 1; i--;) {
items[i].ele.parentNode.insertBefore(items[i].ele, items[i + 1].ele);
}
}
document.addEventListener("click", function(e){
const element = e.target
if (element instanceof HTMLImageElement && element.alt.startsWith('![]('))
expandDesktopImage()
else if (element.tagName == "TH")
sort_table(element)
});

View File

@ -1,34 +0,0 @@
let sortAscending = {};
function sort_table(n) {
const table = this.event.target.parentElement.parentElement.parentElement
const rows = table.rows;
let items = [];
for (let i = 1; i < rows.length; i++) {
const ele = rows[i];
let x = rows[i].getElementsByTagName("TD")[n];
if (!('sortKey' in x.dataset)) {
x = x.getElementsByTagName('a')[0] || x;
}
let attr;
if ('sortKey' in x.dataset) {
attr = x.dataset.sortKey;
} else if ('time' in x.dataset) {
attr = parseInt(x.dataset.time);
} else {
attr = parseInt(x.innerHTML.replace(/,/g, ''));
}
items.push({ ele, attr });
}
if (sortAscending[n]) {
items.sort((a, b) => a.attr > b.attr ? 1 : -1);
sortAscending[n] = false;
} else {
items.sort((a, b) => a.attr < b.attr ? 1 : -1);
sortAscending[n] = true;
}
for (let i = items.length - 1; i--;) {
items[i].ele.parentNode.insertBefore(items[i].ele, items[i + 1].ele);
}
}

View File

@ -307,7 +307,8 @@ class Comment(Base):
if not body: return ""
body = censor_slurs(body, v).replace('<img loading="lazy" data-bs-toggle="tooltip" alt=":marseytrain:" title=":marseytrain:" src="/e/marseytrain.webp">', ':marseytrain:')
body = censor_slurs(body, v).replace('<img loading="lazy" data-bs-toggle="tooltip" alt=":marseytrain:" title=":marseytrain:" src="/e/marseytrain.webp">', ':marseytrain:') \
.replace('<img loading="lazy" data-bs-toggle="tooltip" alt=":marseysleep:" title=":marseysleep:" src="/e/marseysleep.webp">', ':marseysleep:')
return body

View File

@ -153,7 +153,7 @@ class Submission(Base):
elif self.thumburl:
if self.thumburl.startswith('/'): return SITE_FULL + self.thumburl
return self.thumburl
elif self.is_youtube or self.is_video: return f"{SITE_FULL}/i/default_thumb_video.webp?v=1"
elif self.is_youtube or self.is_video: return f"{SITE_FULL}/i/default_thumb_video.webp?v=2"
elif self.is_audio: return f"{SITE_FULL}/i/default_thumb_audio.webp?v=1"
elif self.domain.split('.')[0] == SITE.split('.')[0]:
return f"{SITE_FULL}/i/{SITE_NAME}/site_preview.webp?v=3009"
@ -297,7 +297,7 @@ class Submission(Base):
body += " - <b>WINNER!</b>"
if not winner and v and v.admin_level >= PERMS['POST_BETS_DISTRIBUTE']:
body += f'''<button class="btn btn-primary distribute" data-click2="postToastReload(this,'/distribute/{o.id}')" onclick="areyousure(this)">Declare winner</button>'''
body += f'''<button class="btn btn-primary distribute" data-click="postToastReload(this,'/distribute/{o.id}')" onclick="areyousure(this)">Declare winner</button>'''
body += "</div>"
else:
input_type = 'radio' if o.exclusive else 'checkbox'
@ -329,7 +329,9 @@ class Submission(Base):
body = self.body
if not body: return ""
body = censor_slurs(body, v).replace('<img loading="lazy" data-bs-toggle="tooltip" alt=":marseytrain:" title=":marseytrain:" src="/e/marseytrain.webp">', ':marseytrain:')
body = censor_slurs(body, v).replace('<img loading="lazy" data-bs-toggle="tooltip" alt=":marseytrain:" title=":marseytrain:" src="/e/marseytrain.webp">', ':marseytrain:') \
.replace('<img loading="lazy" data-bs-toggle="tooltip" alt=":marseysleep:" title=":marseysleep:" src="/e/marseysleep.webp">', ':marseysleep:')
body = normalize_urls_runtime(body, v)
return body
@ -346,7 +348,8 @@ class Submission(Base):
def plaintitle(self, v):
title = self.title
title = censor_slurs(title, v).replace('<img loading="lazy" data-bs-toggle="tooltip" alt=":marseytrain:" title=":marseytrain:" src="/e/marseytrain.webp">', ':marseytrain:')
title = censor_slurs(title, v).replace('<img loading="lazy" data-bs-toggle="tooltip" alt=":marseytrain:" title=":marseytrain:" src="/e/marseytrain.webp">', ':marseytrain:') \
.replace('<img loading="lazy" data-bs-toggle="tooltip" alt=":marseysleep:" title=":marseysleep:" src="/e/marseysleep.webp">', ':marseysleep:')
return title

View File

@ -520,9 +520,9 @@ class User(Base):
@property
@lazy
def unban_in(self):
def unban_string(self):
if self.unban_utc == 0:
return "never"
return "permanently banned"
wait = self.unban_utc - int(time.time())
@ -539,43 +539,9 @@ class User(Base):
text = f"{days}d {hours:02d}h {mins:02d}m"
return text
@property
@lazy
def unban_string(self):
text = self.unban_in
if text == "never": return "permanently banned"
return f"Unban in {text}"
@property
@lazy
def unchud_in(self):
if self.agendaposter == 1:
return "never"
wait = self.agendaposter - int(time.time())
if wait < 60:
text = f"{wait}s"
else:
days = wait//(24*60*60)
wait -= days*24*60*60
hours = wait//(60*60)
wait -= hours*60*60
mins = wait//60
text = f"{days}d {hours:02d}h {mins:02d}m"
return text
@property
@lazy
def received_awards(self):

View File

@ -98,7 +98,7 @@ def execute_snappy(post:Submission, v:User):
body += "\n\n"
if post.url and not post.url.startswith(SITE_FULL) and not post.url.startswith('/') and not post.url.startswith(f'https://{BAN_EVASION_DOMAIN}'):
if post.url and not post.url.startswith('/') and not post.url.startswith(SITE_FULL) and not post.url.startswith(BAN_EVASION_FULL):
if post.url.startswith('https://old.reddit.com/r/'):
rev = post.url.replace('https://old.reddit.com/', '')
rev = f"* [unddit.com](https://unddit.com/{rev})\n"
@ -127,7 +127,7 @@ def execute_snappy(post:Submission, v:User):
for href, title in captured:
if href.startswith(SITE_FULL) or href.startswith(f'https://{BAN_EVASION_DOMAIN}'): continue
if href.startswith(SITE_FULL) or href.startswith(BAN_EVASION_FULL): continue
if "Snapshots:\n\n" not in body: body += "Snapshots:\n\n"
if f'**[{title}]({href})**:\n\n' not in body:
addition = f'**[{title}]({href})**:\n\n'

View File

@ -148,6 +148,7 @@ if SITE_NAME == 'rDrama':
"it's almost as if": "I'm a retard but",
"my brother in christ": "my brother in Allah",
"kyle": "Kylie",
"twitter files": 'twitter files <img loading="lazy" data-bs-toggle="tooltip" alt=":marseysleep:" title=":marseysleep:" src="/e/marseysleep.webp">',
}
SLURS.update(RDRAMA_SLURS)
@ -233,7 +234,6 @@ PERMS = { # Minimum admin_level to perform action.
'HOLE_CREATE': 0,
'EDIT_RULES': 3,
'FLAGS_REMOVE': 2,
'VOTES_VISIBLE': 0,
'USER_BLOCKS_VISIBLE': 0,
'USER_FOLLOWS_VISIBLE': 0,
'USER_VOTERS_VISIBLE': 0,
@ -399,6 +399,7 @@ POST_BODY_LENGTH_LIMIT = 20000 # do not make larger than 20000 without altering
POST_BODY_HTML_LENGTH_LIMIT = 40000 # do not make larger than 40000 without altering the table
COMMENT_BODY_LENGTH_LIMIT = 10000 # do not make larger than 10000 characters without altering the table
COMMENT_BODY_HTML_LENGTH_LIMIT = 20000 # do not make larger than 20000 characters without altering the table
CSS_LENGTH_LIMIT = 10000 # do not make larger than 20000 characters without altering the table
COMMENT_MAX_DEPTH = 200
TRANSFER_MESSAGE_LENGTH_LIMIT = 200 # do not make larger than 10000 characters (comment limit) without altering the table
MIN_REPOST_CHECK_URL_LENGTH = 9 # also change the constant in checkRepost() of submit.js
@ -427,38 +428,27 @@ HOLE_REQUIRED = False
HOLE_COST = 0
HOLE_INACTIVITY_DELETION = False
PRIVILEGED_USER_BOTS = ()
GUMROAD_MESSY = ()
AUTOJANNY_ID = 1
SNAPPY_ID = 2
LONGPOSTBOT_ID = 3
ZOZBOT_ID = 4
BASEDBOT_ID = 0
PRIVILEGED_USER_BOTS = ()
SCHIZO_ID = 0
KIPPY_ID = 0
MCCOX_ID = 0
CHIOBU_ID = 0
PIZZASHILL_ID = 0
IMPASSIONATA_ID = 0
HEYMOON_ID = 0
MIMW_ID = 0
SNUS_ID = 0
GUMROAD_MESSY = ()
IDIO_ID = 0
CARP_ID = 0
JOAN_ID = 0
AEVANN_ID = 0
SNAKES_ID = 0
JUSTCOOL_ID = 0
HOMO_ID = 0
SOREN_ID = 0
LAWLZ_ID = 0
DAD_ID = 0
MOM_ID = 0
DONGER_ID = 0
GEESE_ID = 0
BLACKJACKBTZ_ID = 0
TGTW_ID = 0
MODMAIL_ID = 2
GIFT_NOTIF_ID = 5
SIGNUP_FOLLOW_ID = 0
POLL_THREAD = 0
POLL_BET_COINS = 200
@ -473,8 +463,6 @@ SIDEBAR_THREAD = 0
BANNER_THREAD = 0
BADGE_THREAD = 0
SNAPPY_THREAD = 0
GIFT_NOTIF_ID = 5
SIGNUP_FOLLOW_ID = 0
NOTIFICATION_THREAD = 1
MAX_IMAGE_SIZE_BANNER_RESIZED_MB = 1
@ -510,6 +498,8 @@ BADGE_BLACKLIST = { # only grantable by AEVANN_ID and SNAKES_ID except on PCM
137, # Lottery Winner
}
NOTIFIED_USERS = {}
if SITE == 'rdrama.net':
FEATURES['PRONOUNS'] = True
FEATURES['HOUSES'] = True
@ -532,36 +522,58 @@ if SITE == 'rdrama.net':
HOLE_COST = 50000
HOLE_INACTIVITY_DELETION = True
PRIVILEGED_USER_BOTS = (12125,16049)
GUMROAD_MESSY = (1230,1379)
AUTOJANNY_ID = 1046
SNAPPY_ID = 261
LONGPOSTBOT_ID = 1832
ZOZBOT_ID = 1833
PRIVILEGED_USER_BOTS = (12125, 16049)
SCHIZO_ID = 8494
KIPPY_ID = 7150
MCCOX_ID = 8239
CHIOBU_ID = 5214
PIZZASHILL_ID = 2424
IMPASSIONATA_ID = 5800
HEYMOON_ID = 3635
MIMW_ID = 3377
SNUS_ID = 8407
GUMROAD_MESSY = (1230,1379)
IDIO_ID = 30
CARP_ID = 995
JOAN_ID = 28
AEVANN_ID = 1
SNAKES_ID = 10288
JUSTCOOL_ID = 4999
HOMO_ID = 147
SOREN_ID = 2546
LAWLZ_ID = 3833
DAD_ID = 2513
MOM_ID = 4588
DONGER_ID = 541
GEESE_ID = 1710
BLACKJACKBTZ_ID = 12732
TGTW_ID = 2008
NOTIFIED_USERS = {
'aevan': AEVANN_ID,
'avean': AEVANN_ID,
'carp': CARP_ID,
'clit': CARP_ID,
'snakes': SNAKES_ID,
'sneks': SNAKES_ID,
'snekky': SNAKES_ID,
'snekchad': SNAKES_ID,
'jc': JUSTCOOL_ID,
'justcool': JUSTCOOL_ID,
'kippy': KIPPY_ID,
'lawlz': LAWLZ_ID,
'transgirltradwife': TGTW_ID,
'impassionata': IMPASSIONATA_ID,
'pizzashill': PIZZASHILL_ID,
'joan': 28,
'pewkie': 28,
'idio3': 30,
'idio ': 30,
'telegram ': 30,
'the_homocracy': 147,
'donger': 541,
'geese': 1710,
'soren': 2546,
'marseyismywaifu': 3377,
'mimw': 3377,
'heymoon': 3635,
'jollymoon': 3635,
'chiobu': 5214,
'mccox': 8239,
'snus': 8407,
'schizo': 8494,
}
ANTISPAM_BYPASS_IDS = {1703, 13427}
@ -714,46 +726,12 @@ bots = {AUTOJANNY_ID, SNAPPY_ID, LONGPOSTBOT_ID, ZOZBOT_ID, BASEDBOT_ID}
COLORS = {'ff66ac','805ad5','62ca56','38a169','80ffff','2a96f3','eb4963','ff0000','f39731','30409f','3e98a7','e4432d','7b9ae4','ec72de','7f8fa6', 'f8db58','8cdbe6', DEFAULT_COLOR}
BAN_EVASION_DOMAIN = 'stupidpol.site'
BAN_EVASION_FULL = f'https://{BAN_EVASION_DOMAIN}'
DOUBLE_XP_ENABLED = -1 # set to unixtime for when DXP begins, -1 to disable
### COMMENT NOTIFICATIONS ###
NOTIFIED_USERS = {
'aevan': AEVANN_ID,
'avean': AEVANN_ID,
'joan': JOAN_ID,
'pewkie': JOAN_ID,
'carp': CARP_ID,
'idio3': IDIO_ID,
'idio ': IDIO_ID,
'telegram ': IDIO_ID,
'the_homocracy': HOMO_ID,
'schizo': SCHIZO_ID,
'snakes': SNAKES_ID,
'sneks': SNAKES_ID,
'snekky': SNAKES_ID,
'snekchad': SNAKES_ID,
'jc': JUSTCOOL_ID,
'justcool': JUSTCOOL_ID,
'geese': GEESE_ID,
'clit': CARP_ID,
'kippy': KIPPY_ID,
'mccox': MCCOX_ID,
'lawlz': LAWLZ_ID,
'chiobu': CHIOBU_ID,
'donger': DONGER_ID,
'soren': SOREN_ID,
'pizzashill': PIZZASHILL_ID,
'impassionata': IMPASSIONATA_ID,
'heymoon': HEYMOON_ID,
'jollymoon': HEYMOON_ID,
'marseyismywaifu': MIMW_ID,
'mimw': MIMW_ID,
'snus': SNUS_ID,
}
FORTUNE_REPLIES = ('<b style="color:#6023f8">Your fortune: Allah Wills It</b>','<b style="color:#d302a7">Your fortune: Inshallah, Only Good Things Shall Come To Pass</b>','<b style="color:#e7890c">Your fortune: Allah Smiles At You This Day</b>','<b style="color:#7fec11">Your fortune: Your Bussy Is In For A Blasting</b>','<b style="color:#43fd3b">Your fortune: You Will Be Propositioned By A High-Tier Twink</b>','<b style="color:#9d05da">Your fortune: Repent, You Have Displeased Allah And His Vengeance Is Nigh</b>','<b style="color:#f51c6a">Your fortune: Reply Hazy, Try Again</b>','<b style="color:#00cbb0">Your fortune: lmao you just lost 100 coins</b>','<b style="color:#2a56fb">Your fortune: Yikes 😬</b>','<b style="color:#0893e1">Your fortune: You Will Be Blessed With Many Black Bulls</b>','<b style="color:#16f174">Your fortune: NEETmax, The Day Is Lost If You Venture Outside</b>','<b style="color:#fd4d32">Your fortune: A Taste Of Jannah Awaits You Today</b>','<b style="color:#bac200">Your fortune: Watch Your Back</b>','<b style="color:#6023f8">Your fortune: Outlook good</b>','<b style="color:#d302a7">Your fortune: Godly Luck</b>','<b style="color:#e7890c">Your fortune: Good Luck</b>','<b style="color:#7fec11">Your fortune: Bad Luck</b>','<b style="color:#43fd3b">Your fortune: Good news will come to you by mail</b>','<b style="color:#9d05da">Your fortune: Very Bad Luck</b>','<b style="color:#00cbb0">Your fortune: キタ━━━━━━(゚∀゚)━━━━━━ !!!!</b>','<b style="color:#2a56fb">Your fortune: Better not tell you now</b>','<b style="color:#0893e1">Your fortune: You will meet a dark handsome stranger</b>','<b style="color:#16f174">Your fortune:  ´_ゝ`)フーン</b>','<b style="color:#fd4d32">Your fortune: Excellent Luck</b>','<b style="color:#bac200">Your fortune: Average Luck</b>')
FACTCHECK_REPLIES = ('<b style="color:#6023f8">Factcheck: This claim has been confirmed as correct by experts. </b>','<b style="color:#d302a7">Factcheck: This claim has been classified as misogynistic.</b>','<b style="color:#e7890c">Factcheck: This claim is currently being debunked.</b>','<b style="color:#7fec11">Factcheck: This claim is 100% true.</b>','<b style="color:#9d05da">Factcheck: This claim hurts trans lives.</b>','<b style="color:#f51c6a">Factcheck: [REDACTED].</b>','<b style="color:#00cbb0">Factcheck: This claim is both true and false.</b>','<b style="color:#2a56fb">Factcheck: You really believe that shit? Lmao dumbass nigga 🤣</b>','<b style="color:#0893e1">Factcheck: None of this is real.</b>','<b style="color:#16f174">Factcheck: Yes.</b>','<b style="color:#fd4d32">Factcheck: This claim has not been approved by experts.</b>','<b style="color:#bac200">Factcheck: This claim is a gross exageration of reality.</b>','<b style="color:#ff2200">Factcheck: WARNING! THIS CLAIM HAS BEEN CLASSIFIED AS DANGEROUS. PLEASE REMAIN STILL, AN AGENT WILL COME TO MEET YOU SHORTLY.</b>')
EIGHTBALL_REPLIES = ('<b style="color:#7FEC11">The 8-Ball Says: It is certain.</b>', '<b style="color:#7FEC11">The 8-Ball Says: It is decidedly so.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Without a doubt.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Yes definitely.</b>', '<b style="color:#7FEC11">The 8-Ball Says: You may rely on it.</b>', '<b style="color:#7FEC11">The 8-Ball Says: As I see it, yes.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Most likely.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Outlook good.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Yes.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Signs point to yes.</b>', '<b style="color:#E7890C">The 8-Ball Says: Reply hazy, try again.</b>', '<b style="color:#E7890C">The 8-Ball Says: Ask again later.</b>', '<b style="color:#E7890C">The 8-Ball Says: Better not tell you now.</b>', '<b style="color:#E7890C">The 8-Ball Says: Cannot predict now.</b>', '<b style="color:#E7890C">The 8-Ball Says: Concentrate and ask again.</b>', '<b style="color:#FD4D32">The 8-Ball Says: Don\'t count on it.</b>', '<b style="color:#FD4D32">The 8-Ball Says: My reply is no.</b>', '<b style="color:#FD4D32">The 8-Ball Says: My sources say no.</b>', '<b style="color:#FD4D32">The 8-Ball Says: Outlook not so good.</b>', '<b style="color:#FD4D32">The 8-Ball Says: Very doubtful.</b>')
@ -773,12 +751,12 @@ if SITE == 'rdrama.net':
REDDIT_NOTIFS_SITE.add('justice4darrell')
REDDIT_NOTIFS_SITE.add('cringetopia.org')
REDDIT_NOTIFS_USERS = {
'idio3': IDIO_ID,
'idio3': 30,
'aevann': AEVANN_ID,
'carpflo': CARP_ID,
'carpathianflorist': CARP_ID,
'carpathian florist': CARP_ID,
'the_homocracy': HOMO_ID,
'the_homocracy': 147,
'justcool393': JUSTCOOL_ID
}
elif SITE_NAME == 'WPD':
@ -1000,6 +978,9 @@ if SITE_NAME == 'rDrama':
'bungie.net',
'soyjak.party',
'teamblind.com',
'mainchan.com',
'encyclopediadramatica.online',
'thecoli.com',
#fediverse
'rdrama.cc',

View File

@ -236,13 +236,23 @@ MODACTION_TYPES = {
"icon": 'fa-award',
"color": 'bg-primary'
},
'set_new': {
"str": 'changed the default sorting of comments on {self.target_link} to `new`',
"icon": 'fa-sparkles',
"color": 'bg-primary'
},
'set_hot': {
"str": 'changed the default sorting of comments on {self.target_link} to `hot`',
"icon": 'fa-fire',
"color": 'bg-primary'
},
'set_nsfw': {
"str": 'set nsfw on post {self.target_link}',
"str": 'set {self.target_link} as +18',
"icon": 'fa-eye-evil',
"color": 'bg-danger'
},
'set_nsfw_comment': {
"str": 'set nsfw on a {self.target_link}',
"str": 'set {self.target_link} as +18',
"icon": 'fa-eye-evil',
"color": 'bg-danger'
},
@ -302,12 +312,12 @@ MODACTION_TYPES = {
"color": 'bg-muted'
},
'unset_nsfw': {
"str": 'un-set nsfw on post {self.target_link}',
"str": 'unset {self.target_link} as +18',
"icon": 'fa-eye-evil',
"color": 'bg-success'
},
'unset_nsfw_comment': {
"str": 'un-set nsfw on a {self.target_link}',
"str": 'unset {self.target_link} as +18',
"icon": 'fa-eye-evil',
"color": 'bg-success'
},

View File

@ -90,7 +90,11 @@ def _sub_inactive_purge_task():
posts = g.db.query(Submission).filter(Submission.sub.in_(names)).all()
for post in posts:
post.sub = None
if post.sub == 'programming':
post.sub = 'slackernews'
else:
post.sub = None
post.hole_pinned = None
g.db.add(post)

View File

@ -176,7 +176,7 @@ def process_image(filename:str, v, resize=0, trim=False, uploader_id:Optional[in
path = filename.rsplit('/', 1)[0]
kind = path.split('/')[-1]
if kind in ('banners','sidebar','badges'):
if kind in ('banners','sidebar'):
hashes = {}
for img in os.listdir(path):

View File

@ -40,7 +40,7 @@ controversial_regex = re.compile('["> ](https:\/\/old\.reddit\.com/r/[a-zA-Z0-9_
fishylinks_regex = re.compile("https?://\S+", flags=re.A)
spoiler_regex = re.compile('\|\|(.+)\|\|(?![^<]*<\/(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)

View File

@ -58,14 +58,12 @@ def allowed_attributes(tag, name, value):
try: value = int(value.replace('px', ''))
except: return False
if 0 < value <= 250: return True
return False
if tag == 'a':
if name == 'href' and '\\' not in value and 'xn--' not in value:
return True
if name == 'rel' and value == 'nofollow noopener': return True
if name == 'target' and value == '_blank': return True
return False
if tag == 'img':
if name in {'src','data-src'}: return is_safe_url(value)
@ -73,38 +71,33 @@ def allowed_attributes(tag, name, value):
if name == 'data-bs-toggle' and value == 'tooltip': return True
if name in {'g','b','glow'} and not value: return True
if name in {'alt','title'}: return True
return False
if tag == 'lite-youtube':
if name == 'params' and value.startswith('autoplay=1&modestbranding=1'): return True
if name == 'videoid': return True
return False
if tag == 'video':
if name == 'controls' and value == '': return True
if name == 'preload' and value == 'none': return True
if name == 'src': return is_safe_url(value)
return False
if tag == 'audio':
if name == 'src': return is_safe_url(value)
if name == 'controls' and value == '': return True
if name == 'preload' and value == 'none': return True
return False
if tag == 'p':
if name == 'class' and value == 'mb-0': return True
return False
if name == 'class' and value in ('mb-0','resizable'): return True
if tag == 'span':
if name == 'data-bs-toggle' and value == 'tooltip': return True
if name == 'title': return True
if name == 'alt': return True
return False
if tag == 'table':
if name == 'class' and value == 'table': return True
return False
return False
def build_url_re(tlds, protocols):
"""Builds the url regex used by linkifier
@ -370,7 +363,7 @@ def sanitize(sanitized, golden=True, limit_pings=0, showmore=True, count_marseys
sanitized = sanitized.replace(i.group(0), htmlsource)
sanitized = video_sub_regex.sub(r'\1<video controls preload="none" src="\2"></video>', sanitized)
sanitized = video_sub_regex.sub(r'\1<p class="resizable"><video controls preload="none" src="\2"></video></p>', sanitized)
sanitized = audio_sub_regex.sub(r'\1<audio controls preload="none" src="\2"></audio>', sanitized)
if count_marseys:
@ -429,7 +422,6 @@ def allowed_attributes_emojis(tag, name, value):
if name == 'data-bs-toggle' and value == 'tooltip': return True
if name == 'title': return True
if name == 'alt': return True
return False
return False

View File

@ -2,7 +2,7 @@
from files.helpers.config.const import FEATURES
# import flask then...
from flask import g, request, render_template, make_response, redirect, jsonify, send_from_directory, send_file
from flask import g, request, render_template, make_response, redirect, jsonify, send_file
# import our app then...
from files.__main__ import app

View File

@ -1,6 +1,8 @@
import time
from urllib.parse import quote, urlencode
from sqlalchemy import nullslast
from files.__main__ import app, cache, limiter
from files.classes import *
from files.helpers.actions import *
@ -335,7 +337,19 @@ def revert_actions(v:User, username):
@app.get("/admin/shadowbanned")
@admin_level_required(PERMS['USER_SHADOWBAN'])
def shadowbanned(v):
users = g.db.query(User).filter(User.shadowbanned != None).order_by(User.shadowbanned).all()
users = g.db.query(User) \
.filter(
User.shadowbanned != None,
User.truescore > 0,
not_(and_(
User.profileurl.startswith('/e/'),
User.customtitle==None,
User.namecolor == DEFAULT_COLOR,
User.patron == 0,
))
) \
.order_by(nullslast(User.last_active.desc())).all()
return render_template("admin/shadowbanned.html", v=v, users=users)
@ -545,6 +559,8 @@ def badge_grant_post(v):
if '\\' in url: abort(400)
if url.startswith(SITE_FULL):
url = url.split(SITE_FULL, 1)[1]
elif url.startswith(BAN_EVASION_FULL):
url = url.split(BAN_EVASION_FULL, 1)[1]
new_badge.url = url
g.db.add(new_badge)
@ -1075,12 +1091,16 @@ def agendaposter(user_id, v):
try: post = int(request.values["reason"].split("/post/")[1].split(None, 1)[0])
except: abort(400)
post = get_post(post)
if post.sub == 'chudrama':
abort(403, "You can't chud people in /h/chudrama")
post.chuddedfor = f'{duration} by @{v.username}'
g.db.add(post)
elif request.values["reason"].startswith("/comment/"):
try: comment = int(request.values["reason"].split("/comment/")[1].split(None, 1)[0])
except: abort(400)
comment = get_comment(comment)
if comment.post.sub == 'chudrama':
abort(403, "You can't chud people in /h/chudrama")
comment.chuddedfor = f'{duration} by @{v.username}'
g.db.add(comment)

View File

@ -14,17 +14,7 @@ from files.__main__ import app, cache, limiter
ASSET_TYPES = (Marsey, HatDef)
CAN_APPROVE_ASSETS = (AEVANN_ID, CARP_ID, SNAKES_ID)
CAN_UPDATE_ASSETS = (AEVANN_ID, CARP_ID, SNAKES_ID, GEESE_ID, JUSTCOOL_ID)
@app.get('/asset_submissions/<path:path>')
@limiter.exempt
def asset_submissions(path):
resp = make_response(send_from_directory('/asset_submissions', path))
resp.headers.remove("Cache-Control")
resp.headers.add("Cache-Control", "public, max-age=3153600")
resp.headers.remove("Content-Type")
resp.headers.add("Content-Type", "image/webp")
return resp
CAN_UPDATE_ASSETS = (AEVANN_ID, CARP_ID, SNAKES_ID)
@app.get("/submit/marseys")
@auth_required

View File

@ -267,6 +267,10 @@ def award_thing(v, thing_type, id):
else: thing.stickied_utc = t
g.db.add(thing)
elif kind == "agendaposter":
if thing_type == 'post' and thing.sub == 'chudrama' \
or thing_type == 'comment' and thing.post.sub == 'chudrama':
abort(403, "You can't give the chud award in /h/chudrama")
if author.marseyawarded:
abort(409, f"@{author.username} is under the effect of a conflicting award: Marsey award.")

View File

@ -60,7 +60,8 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
context -= 1
top_comment = c
if v: defaultsortingcomments = v.defaultsortingcomments
if post.new: defaultsortingcomments = 'new'
elif v: defaultsortingcomments = v.defaultsortingcomments
else: defaultsortingcomments = "hot"
sort=request.values.get("sort", defaultsortingcomments)
@ -199,7 +200,7 @@ def comment(v:User):
if v.owoify: body_for_sanitize = owoify(body_for_sanitize)
if v.marsify: body_for_sanitize = marsify(body_for_sanitize)
torture = (v.agendaposter and not v.marseyawarded and post_target.sub != 'chudrama' and post_target.id not in ADMIGGER_THREADS)
torture = (v.agendaposter and not v.marseyawarded and not (posting_to_submission and post_target.sub == 'chudrama') and post_target.id not in ADMIGGER_THREADS)
body_html = sanitize(body_for_sanitize, limit_pings=5, count_marseys=not v.marsify, torture=torture)
if post_target.id not in ADMIGGER_THREADS and '!wordle' not in body.lower() and AGENDAPOSTER_PHRASE not in body.lower():

View File

@ -12,20 +12,15 @@ from files.__main__ import app, limiter
def hats(v:User):
owned_hat_ids = [x.hat_id for x in v.owned_hats]
if request.values.get("sort") == 'author_asc':
hats = g.db.query(HatDef, User).join(HatDef.author).filter(HatDef.submitter_id == None).order_by(User.username).all()
elif request.values.get("sort") == 'author_desc':
hats = g.db.query(HatDef, User).join(HatDef.author).filter(HatDef.submitter_id == None).order_by(User.username.desc()).all()
if v.equipped_hat_ids:
equipped = g.db.query(HatDef, User).join(HatDef.author).filter(HatDef.submitter_id == None, HatDef.id.in_(owned_hat_ids), HatDef.id.in_(v.equipped_hat_ids)).order_by(HatDef.price, HatDef.name).all()
not_equipped = g.db.query(HatDef, User).join(HatDef.author).filter(HatDef.submitter_id == None, HatDef.id.in_(owned_hat_ids), HatDef.id.notin_(v.equipped_hat_ids)).order_by(HatDef.price, HatDef.name).all()
owned = equipped + not_equipped
else:
if v.equipped_hat_ids:
equipped = g.db.query(HatDef, User).join(HatDef.author).filter(HatDef.submitter_id == None, HatDef.id.in_(owned_hat_ids), HatDef.id.in_(v.equipped_hat_ids)).order_by(HatDef.price, HatDef.name).all()
not_equipped = g.db.query(HatDef, User).join(HatDef.author).filter(HatDef.submitter_id == None, HatDef.id.in_(owned_hat_ids), HatDef.id.notin_(v.equipped_hat_ids)).order_by(HatDef.price, HatDef.name).all()
owned = equipped + not_equipped
else:
owned = g.db.query(HatDef, User).join(HatDef.author).filter(HatDef.submitter_id == None, HatDef.id.in_(owned_hat_ids)).order_by(HatDef.price, HatDef.name).all()
owned = g.db.query(HatDef, User).join(HatDef.author).filter(HatDef.submitter_id == None, HatDef.id.in_(owned_hat_ids)).order_by(HatDef.price, HatDef.name).all()
not_owned = g.db.query(HatDef, User).join(HatDef.author).filter(HatDef.submitter_id == None, HatDef.id.notin_(owned_hat_ids)).order_by(HatDef.price, HatDef.name).all()
hats = owned + not_owned
not_owned = g.db.query(HatDef, User).join(HatDef.author).filter(HatDef.submitter_id == None, HatDef.id.notin_(owned_hat_ids)).order_by(HatDef.price, HatDef.name).all()
hats = owned + not_owned
sales = g.db.query(func.sum(User.coins_spent_on_hats)).scalar()
num_of_hats = g.db.query(HatDef).filter(HatDef.submitter_id == None).count()

View File

@ -697,6 +697,8 @@ def submit_post(v:User, sub=None):
if url and url.startswith(SITE_FULL):
url = url.split(SITE_FULL)[1]
elif url.startswith(BAN_EVASION_FULL):
url = url.split(BAN_EVASION_FULL, 1)[1]
post = Submission(
private=flag_private,
@ -745,6 +747,11 @@ def submit_post(v:User, sub=None):
post.thumburl = process_image(name2, v, resize=100)
elif file.content_type.startswith('video/'):
post.url = process_video(file, v)
name = f'/images/{time.time()}'.replace('.','') + '.webp'
subprocess.run(['ffmpeg', '-y', '-loglevel', 'warning',
'-i', post.url, '-vf', "scale='min(300,iw)':-2",
'-q:v', '3', '-frames:v', '1', name], check=True)
post.thumburl = name
elif file.content_type.startswith('audio/'):
post.url = process_audio(file, v)
else:
@ -800,8 +807,8 @@ def submit_post(v:User, sub=None):
execute_lawlz_actions(v, post)
if (SITE == 'rdrama.net'
and v.id in (IMPASSIONATA_ID, PIZZASHILL_ID, 2008)
and not (post.sub and post.sub.stealth)):
and v.id in (IMPASSIONATA_ID, PIZZASHILL_ID, TGTW_ID)
and not (post.sub and post.subr.stealth)):
post.stickied_utc = int(time.time()) + 3600
post.stickied = "AutoJanny"
@ -871,9 +878,9 @@ def undelete_post_pid(pid, v):
return {"message": "Post undeleted!"}
@app.post("/toggle_post_nsfw/<pid>")
@app.post("/mark_post_nsfw/<pid>")
@auth_required
def toggle_post_nsfw(pid, v):
def mark_post_nsfw(pid, v):
post = get_post(pid)
if post.author_id != v.id and not v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and not (post.sub and v.mods(post.sub)):
@ -882,13 +889,13 @@ def toggle_post_nsfw(pid, v):
if post.over_18 and v.is_suspended_permanently:
abort(403)
post.over_18 = not post.over_18
post.over_18 = True
g.db.add(post)
if post.author_id != v.id:
if v.admin_level >= PERMS['POST_COMMENT_MODERATION']:
ma = ModAction(
kind = "set_nsfw" if post.over_18 else "unset_nsfw",
kind = "set_nsfw",
user_id = v.id,
target_submission_id = post.id,
)
@ -896,14 +903,48 @@ def toggle_post_nsfw(pid, v):
else:
ma = SubAction(
sub = post.sub,
kind = "set_nsfw" if post.over_18 else "unset_nsfw",
kind = "set_nsfw",
user_id = v.id,
target_submission_id = post.id,
)
g.db.add(ma)
send_repeatable_notification(post.author_id, f"@{v.username} (Admin) has marked [{post.title}](/post/{post.id}) as +18")
if post.over_18: return {"message": "Post has been marked as +18!"}
else: return {"message": "Post has been unmarked as +18!"}
return {"message": "Post has been marked as +18!"}
@app.post("/unmark_post_nsfw/<pid>")
@auth_required
def unmark_post_nsfw(pid, v):
post = get_post(pid)
if post.author_id != v.id and not v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and not (post.sub and v.mods(post.sub)):
abort(403)
if post.over_18 and v.is_suspended_permanently:
abort(403)
post.over_18 = False
g.db.add(post)
if post.author_id != v.id:
if v.admin_level >= PERMS['POST_COMMENT_MODERATION']:
ma = ModAction(
kind = "unset_nsfw",
user_id = v.id,
target_submission_id = post.id,
)
g.db.add(ma)
else:
ma = SubAction(
sub = post.sub,
kind = "unset_nsfw",
user_id = v.id,
target_submission_id = post.id,
)
g.db.add(ma)
send_repeatable_notification(post.author_id, f"@{v.username} (Admin) has unmarked [{post.title}](/post/{post.id}) as +18")
return {"message": "Post has been unmarked as +18!"}
@app.post("/save_post/<pid>")
@limiter.limit(DEFAULT_RATELIMIT_SLOWER)
@ -949,15 +990,46 @@ def pin_post(post_id, v):
else: return {"message": "Post unpinned!"}
return abort(404, "Post not found!")
@app.route("/post/<post_id>/new", methods=["PUT", "DELETE"])
@app.put("/post/<post_id>/new")
@limiter.limit(DEFAULT_RATELIMIT_SLOWER)
@auth_required
def toggle_new_sort(post_id:int, v:User):
def set_new_sort(post_id:int, v:User):
post = get_post(post_id)
if not v.can_edit(post): abort(403, "Only the post author can do that!")
post.new = request.method == "PUT"
post.new = True
g.db.add(post)
return {"message": f"Turned {'on' if post.new else 'off'} sort by new"}
if v.id != post.author_id:
ma = ModAction(
kind = "set_new",
user_id = v.id,
target_submission_id = post.id,
)
g.db.add(ma)
send_repeatable_notification(post.author_id, f"@{v.username} (Admin) has changed the the default sorting of comments on [{post.title}](/post/{post.id}) to `new`")
return {"message": f"Changed the the default sorting of comments on this post to 'new'"}
@app.delete("/post/<post_id>/new")
@limiter.limit(DEFAULT_RATELIMIT_SLOWER)
@auth_required
def unset_new_sort(post_id:int, v:User):
post = get_post(post_id)
if not v.can_edit(post): abort(403, "Only the post author can do that!")
post.new = None
g.db.add(post)
if v.id != post.author_id:
ma = ModAction(
kind = "set_hot",
user_id = v.id,
target_submission_id = post.id,
)
g.db.add(ma)
send_repeatable_notification(post.author_id, f"@{v.username} (Admin) has changed the the default sorting of comments on [{post.title}](/post/{post.id}) to `hot`")
return {"message": f"Changed the the default sorting of comments on this post to 'hot'"}
extensions = IMAGE_FORMATS + VIDEO_FORMATS + AUDIO_FORMATS

View File

@ -46,7 +46,6 @@ def check_for_alts(current:User, include_current_session=True):
past_accs.remove(past_id)
continue
if past_id == MOM_ID or current_id == MOM_ID: break
if past_id == current_id: continue
li = [past_id, current_id]

View File

@ -225,7 +225,14 @@ def searchcomments(v:User):
if v.admin_level < PERMS['POST_COMMENT_MODERATION']:
private = [x[0] for x in g.db.query(Submission.id).filter(Submission.private == True).all()]
comments = comments.filter(Comment.is_banned==False, Comment.deleted_utc == 0, Comment.parent_submission.notin_(private))
comments = comments.filter(
Comment.is_banned==False,
Comment.deleted_utc == 0,
or_(
Comment.parent_submission.notin_(private),
Comment.wall_user_id != None
)
)
if 'after' in criteria:

View File

@ -342,9 +342,6 @@ def settings_personal_post(v):
if house == "None": house = ''
v.house = house
if v.house == "Vampire":
send_repeatable_notification(DAD_ID, f"@{v.username} has joined House Vampire!")
updated = True
if updated:
@ -602,7 +599,7 @@ def settings_css_get(v:User):
@ratelimit_user()
def settings_css(v):
if v.agendaposter: abort(400, "Agendapostered users can't edit CSS!")
css = request.values.get("css", v.css).strip().replace('\\', '').strip()[:4000]
css = request.values.get("css", v.css).strip().replace('\\', '').strip()[:CSS_LENGTH_LIMIT]
if '</style' in css.lower():
abort(400, "Please message @Aevann if you get this error")
v.css = css
@ -615,7 +612,7 @@ def settings_css(v):
@auth_required
@ratelimit_user()
def settings_profilecss(v):
profilecss = request.values.get("profilecss", v.profilecss).strip().replace('\\', '').strip()[:4000]
profilecss = request.values.get("profilecss", v.profilecss).strip().replace('\\', '').strip()[:CSS_LENGTH_LIMIT]
valid, error = validate_css(profilecss)
if not valid:
return render_template("settings/css.html", error=error, v=v)

View File

@ -245,75 +245,6 @@ def submit_contact(v):
def archivesindex():
return redirect("/archives/index.html")
@app.get('/archives/<path:path>')
def archives(path):
resp = make_response(send_from_directory('/archives', path))
if request.path.endswith('.css'): resp.headers.add("Content-Type", "text/css")
return resp
def static_file(dir:str, path:str, should_cache:bool, is_webp:bool) -> Response:
resp = make_response(send_from_directory(dir, path))
if should_cache:
resp.headers.remove("Cache-Control")
resp.headers.add("Cache-Control", "public, max-age=3153600")
if is_webp:
resp.headers.remove("Content-Type")
resp.headers.add("Content-Type", "image/webp")
return resp
@app.get('/e/<emoji>')
@limiter.exempt
def emoji(emoji):
if not emoji.endswith('.webp'): abort(404)
return static_file('assets/images/emojis', emoji, True, True)
@app.get('/icon.webp')
@limiter.exempt
def icon():
return static_file('assets/images', f'{SITE_NAME}/icon.webp', True, True)
@app.get('/i/<path:path>')
@limiter.exempt
def image(path):
is_webp = path.endswith('.webp')
return static_file('assets/images', path, is_webp or path.endswith('.gif') or path.endswith('.ttf') or path.endswith('.woff2'), is_webp)
@app.get('/assets/<path:path>')
@app.get('/static/assets/<path:path>')
@limiter.exempt
def static_service(path):
if path.startswith(f'app_{SITE_NAME}_v'):
return redirect('/app')
is_webp = path.endswith('.webp')
return static_file('assets', path, is_webp or path.endswith('.gif') or path.endswith('.ttf') or path.endswith('.woff2'), is_webp)
### BEGIN FALLBACK ASSET SERVING
# In production, we have nginx serve these locations now.
# These routes stay for local testing. Requests don't reach them on prod.
@app.get('/images/<path>')
@app.get('/hostedimages/<path>')
@app.get("/static/images/<path>")
@limiter.exempt
def images(path):
return static_file('/images', path, True, True)
@app.get('/videos/<path>')
@limiter.exempt
def videos(path):
return static_file('/videos', path, True, False)
@app.get('/audio/<path>')
@limiter.exempt
def audio(path):
return static_file('/audio', path, True, False)
### END FALLBACK ASSET SERVING
@app.get("/robots.txt")
def robots_txt():
return send_file("assets/robots.txt")
no = (21,22,23,24,25,26,27)
@cache.memoize(timeout=3600)
@ -350,16 +281,6 @@ def blocks(v):
return render_template("blocks.html", v=v, users=users, targets=targets)
@app.get("/banned")
@auth_required
def banned(v:User):
after_30_days = int(time.time()) + 86400 * 30
users = g.db.query(User).filter(User.is_banned > 0, or_(User.unban_utc == 0, User.unban_utc > after_30_days))
if not v.can_see_shadowbanned:
users = users.filter(User.shadowbanned == None)
users = users.all()
return render_template("banned.html", v=v, users=users)
@app.get("/formatting")
@auth_required
def formatting(v:User):

View File

@ -7,6 +7,7 @@ from typing import Literal
import gevent
import qrcode
from sqlalchemy import nullslast
from sqlalchemy.orm import aliased
from files.classes import *
@ -167,11 +168,34 @@ def user_voted_posts(v:User, username):
def user_voted_comments(v:User, username):
return user_voted(v, username, Comment, CommentVote, "userpage/voted_comments.html", True)
@app.get("/banned")
@auth_required
def banned(v:User):
users = g.db.query(User).filter(
User.is_banned > 0,
User.truescore > 0,
or_(User.unban_utc == 0, User.unban_utc > time.time()),
not_(and_(
User.profileurl.startswith('/e/'),
User.customtitle==None,
User.namecolor == DEFAULT_COLOR,
User.patron == 0,
))
)
if v.admin_level >= PERMS['VIEW_LAST_ACTIVE']:
users = users.order_by(nullslast(User.last_active.desc()))
if not v.can_see_shadowbanned:
users = users.filter(User.shadowbanned == None)
users = users.all()
return render_template("banned.html", v=v, users=users)
@app.get("/grassed")
@auth_required
def grassed(v:User):
users = g.db.query(User).filter(User.ban_reason.like('grass award used by @%'))
users = g.db.query(User).filter(
User.ban_reason.like('grass award used by @%'),
User.unban_utc > time.time(),
)
if not v.can_see_shadowbanned:
users = users.filter(User.shadowbanned == None)
users = users.all()
@ -180,8 +204,18 @@ def grassed(v:User):
@app.get("/chuds")
@auth_required
def chuds(v:User):
after_30_days = int(time.time()) + 86400 * 30
users = g.db.query(User).filter(or_(User.agendaposter == 1, User.agendaposter > after_30_days))
users = g.db.query(User).filter(
User.truescore > 0,
or_(User.agendaposter == 1, User.agendaposter > time.time()),
not_(and_(
User.profileurl.startswith('/e/'),
User.customtitle==None,
User.namecolor == DEFAULT_COLOR,
User.patron == 0,
))
)
if v.admin_level >= PERMS['VIEW_LAST_ACTIVE']:
users = users.order_by(nullslast(User.last_active.desc()))
if not v.can_see_shadowbanned:
users = users.filter(User.shadowbanned == None)
users = users.order_by(User.username).all()
@ -389,17 +423,9 @@ def get_profilecss(id):
@app.get("/@<username>/song")
def usersong(username:str):
user = get_user(username)
if user.song: return redirect(f"/song/{user.song}.mp3")
if user.song: return redirect(f"/songs/{user.song}.mp3")
else: abort(404)
@app.get("/song/<song>")
@app.get("/static/song/<song>")
def song(song):
resp = make_response(send_from_directory('/songs', song))
resp.headers.remove("Cache-Control")
resp.headers.add("Cache-Control", "public, max-age=3153600")
return resp
@app.post("/subscribe/<post_id>")
@limiter.limit(DEFAULT_RATELIMIT_SLOWER)
@auth_required
@ -445,13 +471,13 @@ def message2(v:User, username:str):
body_html = sanitize(message)
if not (SITE == 'rdrama.net' and user.id == BLACKJACKBTZ_ID):
existing = g.db.query(Comment.id).filter(Comment.author_id == v.id,
Comment.sentto == user.id,
Comment.body_html == body_html,
).first()
existing = g.db.query(Comment.id).filter(
Comment.author_id == v.id,
Comment.sentto == user.id,
Comment.body_html == body_html
).first()
if existing: abort(403, "Message already exists.")
if existing: abort(403, "Message already exists.")
c = Comment(author_id=v.id,
parent_submission=None,
@ -727,11 +753,6 @@ def u_username_wall(v:Optional[User], username:str):
is_following = v and u.has_follower(v)
if not u.is_visible_to(v):
if g.is_api_or_xhr or request.path.endswith(".json"):
abort(403, f"@{u.username}'s userpage is private")
return render_template("userpage/private.html", u=u, v=v, is_following=is_following), 403
if v and v.id != u.id:
g.db.flush()
view = g.db.query(ViewerRelationship).filter_by(viewer_id=v.id, user_id=u.id).one_or_none()

View File

@ -6,7 +6,7 @@ from files.__main__ import app, limiter
@app.get("/votes/<link>")
@admin_level_required(PERMS['VOTES_VISIBLE'])
@auth_required
def vote_info_get(v, link):
try:
if "p_" in link: thing = get_post(int(link.split("p_")[1]), v=v)

View File

@ -56,7 +56,7 @@
<p>Two accounts controlled by different people should have most uniqueness percentages at or above 70-80%</p>
<p>A sockpuppet account will have its uniqueness percentages significantly lower.</p>
<button class="btn btn-danger" data-click2="postToastReload(this,'/@{{u1.username}}/alts/?other_username={{u2.username}}')" onclick="areyousure(this)">Link {{u1.username}} and {{u2.username}}</button>
<button class="btn btn-danger" data-click="postToastReload(this,'/@{{u1.username}}/alts/?other_username={{u2.username}}')" onclick="areyousure(this)">Link {{u1.username}} and {{u2.username}}</button>
{% endif %}
{% endif %}
{% endif %}

View File

@ -61,8 +61,8 @@
<form onsubmit="return false;">
<label for="link-input-other">Other Username</label>
<input autocomplete="off" id="link-input-other" type="text" class="form-control mb-2" name="other_username" placeholder="Other Username">
<button id="add-alt-form-link" class="btn btn-danger mr-3" data-click2="submitAddAlt(this)" onclick="areyousure(this)">Add Alt Linked</button>
<button id="add-alt-form-delink" class="btn btn-danger" data-click2="submitAddAlt(this)" onclick="areyousure(this)">Add Alt Delinked</button>
<button id="add-alt-form-link" class="btn btn-danger mr-3" data-click="submitAddAlt(this)" onclick="areyousure(this)">Add Alt Linked</button>
<button id="add-alt-form-delink" class="btn btn-danger" data-click="submitAddAlt(this)" onclick="areyousure(this)">Add Alt Delinked</button>
</form>
</section>
{% endif %}

View File

@ -18,10 +18,10 @@
<div class="overflow-x-auto"><table class="table table-striped">
<thead class="bg-primary text-white">
<tr>
<th scope="col">Select</th>
<th scope="col">Image</th>
<th scope="col">Name</th>
<th scope="col">Default Description</th>
<th>Select</th>
<th>Image</th>
<th>Name</th>
<th>Default Description</th>
</tr>
</thead>
<tbody>

View File

@ -8,6 +8,8 @@
<tr>
<th>#</th>
<th>Name</th>
<th>Last Active</th>
<th>Truescore</th>
<th>Shadowbanned by</th>
<th>Shadowban reason</th>
</tr>
@ -15,11 +17,15 @@
{% for user in users %}
<tr>
<td>{{loop.index}}</td>
<td>{% include "user_in_table.html" %}</td>
<td data-sort-key="{{user.username.lower() if user else ''}}">{%- include 'user_in_table.html' -%}</td>
<td {% if user.last_active %}data-time="{{user.last_active}}"{% endif %}></td>
<td>{{user.truescore}}</td>
<td>{{user.shadowbanned}}</td>
<td>{{user.ban_reason}}</td>
<td>{% if user.ban_reason %}{{user.ban_reason}}{% endif %}</td>
</tr>
{% endfor %}
</table>
{% endblock %}

View File

@ -12,8 +12,8 @@
<tr>
<th>#</th>
<th>Name</th>
<th onclick="sort_table(2)" style="text-align:right;">Truescore</th>
<th onclick="sort_table(3)" style="text-align:right;">Mod actions</th>
<th style="text-align:right;">Truescore</th>
<th style="text-align:right;">Mod actions</th>
</tr>
</thead>
@ -28,6 +28,6 @@
</table>
</div>
<script defer src="{{'js/sort_table.js' | asset}}"></script>
{% endblock %}

View File

@ -7,12 +7,12 @@
<table class="table table-striped mb-5">
<thead class="bg-primary text-white">
<tr>
<th onclick="sort_table(0)">#</th>
<th>#</th>
<th>Name</th>
<th>Image</th>
<th>Description</th>
<th onclick="sort_table(4)">#</th>
<th onclick="sort_table(4)">Rarity</th>
<th>#</th>
<th>Rarity</th>
</tr>
</thead>
@ -32,6 +32,6 @@
</table>
</div>
<script defer src="{{'js/sort_table.js' | asset}}"></script>
{% endblock %}

View File

@ -2,12 +2,16 @@
{% block pagetitle %}Banned Users{% endblock %}
{% block content %}
<h5 class="my-4">Users who are permabanned or have more than 30 days to be unbanned</h5>
<h5 class="my-4">Banned Users</h5>
<div class="overflow-x-auto"><table class="table table-striped mb-5">
<thead class="bg-primary text-white">
<tr>
<th>#</th>
<th>Name</th>
{% if v and v.admin_level >= PERMS['VIEW_LAST_ACTIVE'] -%}
<th>Last Active</th>
{%- endif %}
<th>Truescore</th>
<th>Ban reason</th>
<th>Banned by</th>
<th>Unban in</th>
@ -17,17 +21,21 @@
<tr>
<td>{{loop.index}}</td>
<td>{% include "user_in_table.html" %}</td>
{% if v and v.admin_level >= PERMS['VIEW_LAST_ACTIVE'] -%}
<td {% if user.last_active %}data-time="{{user.last_active}}"{% endif %}></td>
{%- endif %}
<td>{{user.truescore}}</td>
<td>{% if user.ban_reason %}{{user.ban_reason}}{% endif %}</td>
<td>
{% with user=user.banned_by %}
{% include "user_in_table.html" %}
{% endwith %}
</td>
<td>
{{user.unban_in}}
{% with user=user.banned_by %}
<td data-sort-key="{{user.username.lower() if user else ''}}">
{% include "user_in_table.html" %}
</td>
{% endwith %}
<td {% if user.unban_utc %}data-time="{{user.unban_utc}}"{% endif %}></td>
</tr>
{% endfor %}
</table>
{% endblock %}

View File

@ -2,12 +2,16 @@
{% block pagetitle %}Chuds{% endblock %}
{% block content %}
<h5 class="my-4">Users who are permachudded or have more than 30 days to be unchudded</h5>
<h5 class="my-4">Chudded Users</h5>
<div class="overflow-x-auto"><table class="table table-striped mb-5">
<thead class="bg-primary text-white">
<tr>
<th>#</th>
<th>Name</th>
{% if v and v.admin_level >= PERMS['VIEW_LAST_ACTIVE'] -%}
<th>Last Active</th>
{%- endif %}
<th>Truescore</th>
<th>Unchud in</th>
</tr>
</thead>
@ -15,8 +19,15 @@
<tr>
<td>{{loop.index}}</td>
<td>{% include "user_in_table.html" %}</td>
<td>{{user.unchud_in}}</td>
{% if v and v.admin_level >= PERMS['VIEW_LAST_ACTIVE'] -%}
<td {% if user.last_active %}data-time="{{user.last_active}}"{% endif %}></td>
{%- endif %}
<td>{{user.truescore}}</td>
<td {% if user.agendaposter != 1 %}data-time="{{user.agendaposter}}"{% endif %}></td>
</tr>
{% endfor %}
</table>
{% endblock %}

View File

@ -297,7 +297,7 @@
</label>
</div>
<button type="button" id="edit-btn-{{c.id}}" form="comment-edit-form-{{c.id}}" class="btn btn-primary ml-2 fl-r commentmob" onclick="comment_edit('{{c.id}}');remove_dialog()">Save Edit</button>
<button type="button" id="cancel-edit-{{c.id}}" onclick="toggleEdit('{{c.id}}');remove_dialog()" class="btn btn-link text-muted ml-auto cancel-form fl-r commentmob">Cancel</button>
<button type="button" id="cancel-edit-{{c.id}}" onclick="toggleEdit('{{c.id}}');remove_dialog()" class="btn btn-link text-muted ml-auto fl-r commentmob">Cancel</button>
</form>
<div id="preview-edit-{{c.id}}" class="preview mb-3 mt-5"></div>
<div class="form-text text-small p-0 m-0"><a href="/formatting" {% if v and v.newtab %}data-target="t" target="_blank"{% endif %}>Formatting help</a></div>
@ -397,7 +397,9 @@
{% endif %}
{% if v and ((not c.ghost and v.admin_level >= PERMS['VOTES_VISIBLE']) or v.id == AEVANN_ID) %}<a href="/votes/{{c.fullname}}" class="btn caction nobackground px-1 text-muted"><i class="fas fa-arrows-v"></i>Votes</a>{% endif %}
{% if not c.ghost or (v and v.id == AEVANN_ID) %}
<a href="/votes/{{c.fullname}}" class="btn caction nobackground px-1 text-muted"><i class="fas fa-arrows-v"></i>Votes</a>
{% endif %}
<a class="btn caction nobackground px-1 text-muted" href="{{c.permalink}}"><i class="fas fa-book-open"></i>Context</a>
@ -556,7 +558,7 @@
{% endif %}
</div>
<button type="button" onclick="document.getElementById('reply-message-{{c.id}}').classList.add('d-none');remove_dialog()" class="btn btn-link text-muted ml-auto cancel-form">Cancel</button>
<button type="button" onclick="document.getElementById('reply-message-{{c.id}}').classList.add('d-none');remove_dialog()" class="btn btn-link text-muted ml-auto">Cancel</button>
<button type="button" id="save-reply-to-{{c.id}}" class="btn btn-primary ml-2" onclick="post_reply('{{c.id}}');remove_dialog()">Reply</button>
</form>
<div id="message-reply-{{c.id}}" class="preview mt-2"></div>
@ -581,7 +583,9 @@
<div class="modal-body">
<ul class="list-group comment-actions">
{% if v and ((not c.ghost and v.admin_level >= PERMS['VOTES_VISIBLE']) or v.id == AEVANN_ID) %}<a href="/votes/{{c.fullname}}"><li class="list-group-item"><i class="fas fa-arrows-v mr-2"></i>Votes</li></a>{% endif %}
{% if not c.ghost or (v and v.id == AEVANN_ID) %}
<a href="/votes/{{c.fullname}}"><li class="list-group-item"><i class="fas fa-arrows-v mr-2"></i>Votes</li></a>
{% endif %}
<a class="list-group-item" href="{{c.permalink}}"><i class="fas fa-book-open mr-2"></i>Context</a>
@ -612,7 +616,7 @@
{% if not c.ghost %}
<button type="button" id="unblock2-{{c.id}}" data-bs-dismiss="modal" class="text-success list-group-item {% if not c.is_blocking %}d-none{% endif %}" onclick="postToastSwitch(this,'/settings/unblock?username={{c.author.username}}','block2-{{c.id}}','unblock2-{{c.id}}','d-none')"><i class="fas fa-eye-slash text-success mr-2"></i>Unblock user</button>
<button type="button" id="block2-{{c.id}}" class="{% if c.is_blocking %}d-none{% endif %} list-group-item text-danger" data-click2="postToastSwitch(this,'/settings/block?username={{c.author.username}}','block2-{{c.id}}','unblock2-{{c.id}}','d-none')" onclick="areyousure(this)" data-dismiss="modal"><i class="fas fa-eye-slash fa-fw text-danger mr-2"></i>Block user</button>
<button type="button" id="block2-{{c.id}}" class="{% if c.is_blocking %}d-none{% endif %} list-group-item text-danger" data-click="postToastSwitch(this,'/settings/block?username={{c.author.username}}','block2-{{c.id}}','unblock2-{{c.id}}','d-none')" onclick="areyousure(this)" data-dismiss="modal"><i class="fas fa-eye-slash fa-fw text-danger mr-2"></i>Block user</button>
{% endif %}
{% endif %}

View File

@ -68,7 +68,9 @@ Text 2
<td>Video Files</td>
<td>https://files.catbox.moe/v4om92.mp4</td>
<td>
<video controls preload="none" src="https://files.catbox.moe/v4om92.mp4"></video>
<p class="resizable">
<video controls preload="none" src="https://files.catbox.moe/v4om92.mp4"></video>
</p>
</td>
</tr>
<tr>

View File

@ -77,25 +77,16 @@
<table class="table table-striped shop">
<thead class="bg-primary text-white">
<tr>
<th scope="col">Hat</th>
<th scope="col">Name</th>
<th scope="col">Description</th>
<th>Hat</th>
<th>Name</th>
<th>Description</th>
{% if SITE == 'rdrama.net' %}
{% if request.values.get("sort") == 'author_asc' %}
<th scope="col"><a href="?sort=author_desc">Author</a></th>
{% else %}
<th scope="col"><a href="?sort=author_asc">Author</a></th>
{% endif %}
<th scope="col" onclick="sort_table(4)">Owners</th>
<th scope="col" onclick="sort_table(5)">Price</th>
<th scope="col">Actions</th>
<th scope="col" onclick="sort_table(7)">Added on</th>
{% else %}
<th scope="col" onclick="sort_table(3)">Owners</th>
<th scope="col" onclick="sort_table(4)">Price</th>
<th scope="col">Actions</th>
<th scope="col" onclick="sort_table(6)">Added on</th>
<th>Author</a></th>
{% endif %}
<th>Owners</th>
<th>Price</th>
<th>Actions</th>
<th>Added on</th>
</tr>
</thead>
@ -118,10 +109,10 @@
<td class="shop-table-actions" style="width:unset">
{% if hat.id not in owned_hat_ids and hat.is_purchasable %}
<div id="if-not-owned-{{hat.id}}">
<button type="button" id="buy1-{{hat.id}}" class="btn btn-success {% if v.coins < hat.price %}disabled{% endif %}" data-click2="postToastSwitch(this, '/buy_hat/{{hat.id}}', 'if-not-owned-{{hat.id}}', 'if-owned-{{hat.id}}', 'd-none', (xhr)=>{if(xhr.status == 200)document.getElementById('user-coins-amount').innerHTML-={{hat.price}}})" onclick="areyousure(this)"><span class="m-auto">Buy</span></button>
<button type="button" id="buy1-{{hat.id}}" class="btn btn-success {% if v.coins < hat.price %}disabled{% endif %}" data-click="postToastSwitch(this, '/buy_hat/{{hat.id}}', 'if-not-owned-{{hat.id}}', 'if-owned-{{hat.id}}', 'd-none', (xhr)=>{if(xhr.status == 200)document.getElementById('user-coins-amount').innerHTML-={{hat.price}}})" onclick="areyousure(this)"><span class="m-auto">Buy</span></button>
{% if FEATURES['MARSEYBUX'] %}
<button type="button" id="buy2-{{hat.id}}" class="marseybux btn btn-success {% if v.marseybux < hat.price %}disabled{% endif %}" data-click2="postToastSwitch(this, '/buy_hat/{{hat.id}}?mb=true', 'if-not-owned-{{hat.id}}', 'if-owned-{{hat.id}}', 'd-none', (xhr)=>{if(xhr.status == 200)document.getElementById('user-bux-amount').innerHTML-={{hat.price}}})" onclick="areyousure(this)"><span class="m-auto">MBux</span></button>
<button type="button" id="buy2-{{hat.id}}" class="marseybux btn btn-success {% if v.marseybux < hat.price %}disabled{% endif %}" data-click="postToastSwitch(this, '/buy_hat/{{hat.id}}?mb=true', 'if-not-owned-{{hat.id}}', 'if-owned-{{hat.id}}', 'd-none', (xhr)=>{if(xhr.status == 200)document.getElementById('user-bux-amount').innerHTML-={{hat.price}}})" onclick="areyousure(this)"><span class="m-auto">MBux</span></button>
{% endif %}
</div>
{% endif %}
@ -138,5 +129,5 @@
{% endfor %}
</tbody>
</table>
<script defer src="{{'js/sort_table.js' | asset}}"></script>
{% endblock %}

Some files were not shown because too many files have changed in this diff Show More