gfds
This commit is contained in:
@@ -11,26 +11,26 @@ import url from "url";
|
||||
const getGlobalfilter = (session) => {
|
||||
if (!cfg.nsfp?.length) return null;
|
||||
let filteredTags = [...cfg.nsfp];
|
||||
// For anonymous users, respect their allowed_modes permissions
|
||||
// allowed_modes controls access to NSFW/NSFL for anon/guests by stripping the RATING tags
|
||||
// (tag_id 2 = NSFW, nsfl_tag_id = NSFL) from the nsfp filter.
|
||||
// Any other nsfp tags (content-specific blocks) are never stripped — they always apply.
|
||||
const nsflId = parseInt(cfg.nsfl_tag_id, 10) || 3;
|
||||
if (session && isAnonSession(session)) {
|
||||
const allowedModes = getAnonAllowedModes();
|
||||
if (allowedModes.includes('nsfw')) {
|
||||
filteredTags = filteredTags.filter(id => id !== 2);
|
||||
}
|
||||
const nsflId = parseInt(cfg.nsfl_tag_id, 10) || 3;
|
||||
if (allowedModes.includes('nsfl')) {
|
||||
filteredTags = filteredTags.filter(id => id !== nsflId);
|
||||
}
|
||||
} else if (!session) {
|
||||
// Guest (not logged in): use public_nsfw setting
|
||||
// Guest (not logged in): use public_nsfw / public_nsfl settings
|
||||
if (cfg.websrv.public_nsfw) {
|
||||
filteredTags = filteredTags.filter(id => id !== 2);
|
||||
}
|
||||
} else {
|
||||
// Logged-in member: use public_nsfw setting
|
||||
if (cfg.websrv.public_nsfw) {
|
||||
filteredTags = filteredTags.filter(id => id !== 2);
|
||||
}
|
||||
// Logged-in member: rating tags are not filtered by nsfp
|
||||
filteredTags = filteredTags.filter(id => id !== 2 && id !== nsflId);
|
||||
}
|
||||
return filteredTags.length ? filteredTags.map(n => `tag_id = ${n}`).join(" or ") : null;
|
||||
};
|
||||
@@ -363,7 +363,8 @@ const buildFeedFilters = async ({
|
||||
rawUserHallOwner,
|
||||
rawTagger
|
||||
}) => {
|
||||
const user = rawUser ? lib.escapeLike(decodeURI(rawUser)) : null;
|
||||
const user = rawUser ? decodeURI(rawUser) : null;
|
||||
const userLike = user ? lib.escapeLike(user) : null;
|
||||
|
||||
// --- title: prefix — search items.title instead of the tags table ---
|
||||
const _decodedTag = rawTag ? decodeURIComponent(rawTag) : '';
|
||||
@@ -485,6 +486,7 @@ const buildFeedFilters = async ({
|
||||
|
||||
return {
|
||||
user,
|
||||
userLike,
|
||||
_decodedTag,
|
||||
isTitleSearch,
|
||||
titleQuery,
|
||||
@@ -568,6 +570,7 @@ const f0cklib = {
|
||||
|
||||
const {
|
||||
user,
|
||||
userLike,
|
||||
mimeSQL,
|
||||
excludedTags,
|
||||
newerThan,
|
||||
@@ -591,8 +594,8 @@ const f0cklib = {
|
||||
${visibilityFilter}
|
||||
${tagFilter}
|
||||
${titleFilter}
|
||||
${fav ? db`and (fav_u.user ilike ${user} or fav_u.login ilike ${user})` : db``}
|
||||
${!fav && user ? db`and items.username ilike ${user}` : db``}
|
||||
${fav ? db`and (fav_u.user ilike ${userLike} or fav_u.login ilike ${userLike})` : db``}
|
||||
${!fav && user ? db`and items.username ilike ${userLike}` : db``}
|
||||
${mimeSQL}
|
||||
${hallFilter}
|
||||
${userHallFilter}
|
||||
@@ -617,8 +620,8 @@ const f0cklib = {
|
||||
${visibilityFilter}
|
||||
${tagFilter}
|
||||
${titleFilter}
|
||||
${fav ? db`and (fav_u.user ilike ${user} or fav_u.login ilike ${user})` : db``}
|
||||
${!fav && user ? db`and items.username ilike ${user}` : db``}
|
||||
${fav ? db`and (fav_u.user ilike ${userLike} or fav_u.login ilike ${userLike})` : db``}
|
||||
${!fav && user ? db`and items.username ilike ${userLike}` : db``}
|
||||
${mimeSQL}
|
||||
${hallFilter}
|
||||
${userHallFilter}
|
||||
@@ -680,6 +683,7 @@ const f0cklib = {
|
||||
|
||||
const {
|
||||
user,
|
||||
userLike,
|
||||
_decodedTag,
|
||||
isTitleSearch,
|
||||
titleQuery,
|
||||
@@ -747,8 +751,8 @@ const f0cklib = {
|
||||
${tagFilter}
|
||||
${titleFilter}
|
||||
${idsFilter}
|
||||
${fav && user ? db`and (fav_u.user ilike ${user} or fav_u.login ilike ${user})` : db``}
|
||||
${!fav && user ? db`and items.username ilike ${user}` : db``}
|
||||
${fav && user ? db`and (fav_u.user ilike ${userLike} or fav_u.login ilike ${userLike})` : db``}
|
||||
${!fav && user ? db`and items.username ilike ${userLike}` : db``}
|
||||
${mimeSQL}
|
||||
${hallFilter}
|
||||
${userHallFilter}
|
||||
@@ -791,8 +795,8 @@ const f0cklib = {
|
||||
${tagFilter}
|
||||
${titleFilter}
|
||||
${idsFilter}
|
||||
${fav && user ? db`and (fav_u.user ilike ${user} or fav_u.login ilike ${user})` : db``}
|
||||
${!fav && user ? db`and items.username ilike ${user}` : db``}
|
||||
${fav && user ? db`and (fav_u.user ilike ${userLike} or fav_u.login ilike ${userLike})` : db``}
|
||||
${!fav && user ? db`and items.username ilike ${userLike}` : db``}
|
||||
${mimeSQL}
|
||||
${hallFilter}
|
||||
${userHallFilter}
|
||||
@@ -1089,7 +1093,8 @@ const f0cklib = {
|
||||
: (typeof ids === 'string' ? ids.split(',').map(Number).filter(n => Number.isInteger(n) && n > 0) : null);
|
||||
const idsFilter = (cleanIds && cleanIds.length > 0) ? db`and items.id = ANY(${cleanIds}::int[])` : db``;
|
||||
|
||||
const user = rawUser ? lib.escapeLike(decodeURI(rawUser)) : null;
|
||||
const user = rawUser ? decodeURI(rawUser) : null;
|
||||
const userLike = user ? lib.escapeLike(user) : null;
|
||||
|
||||
// --- title: prefix — search items.title instead of the tags table ---
|
||||
const _decodedTag = rawTag ? decodeURIComponent(rawTag) : '';
|
||||
@@ -1222,8 +1227,8 @@ const f0cklib = {
|
||||
${titleFilter}
|
||||
${hallFilter}
|
||||
${userHallFilter}
|
||||
${fav && user ? db`and "user"."user" ilike ${user}` : db``}
|
||||
${!fav && user ? db`and items.username ilike ${user}` : db``}
|
||||
${fav && user ? db`and "user"."user" ilike ${userLike}` : db``}
|
||||
${!fav && user ? db`and items.username ilike ${userLike}` : db``}
|
||||
${idsFilter}
|
||||
${mimeSQL}
|
||||
${(!session || isAnonSession(session)) && getGlobalfilter(session) ? db`and not exists (select 1 from tags_assign where item_id = items.id and (${db.unsafe(getGlobalfilter(session))}))` : db``}
|
||||
@@ -1579,17 +1584,22 @@ const f0cklib = {
|
||||
}
|
||||
}
|
||||
|
||||
const parentRatingTags = tags.filter(t => t.id == 1 || t.id == 2 || (cfg.enable_nsfl && (t.id == nsfl_id || t.normalized === 'nsfl')));
|
||||
|
||||
const isSubVisible = (subTags) => {
|
||||
if (bypass_filter) return true;
|
||||
|
||||
const subIsNsfl = cfg.enable_nsfl && subTags.some(t => t.id == nsfl_id || t.normalized === 'nsfl');
|
||||
const subIsNsfw = subTags.some(t => t.id == 2);
|
||||
const subIsSfw = subTags.some(t => t.id == 1);
|
||||
const hasSubRating = subTags.some(t => t.id == 1 || t.id == 2 || (cfg.enable_nsfl && (t.id == nsfl_id || t.normalized === 'nsfl')));
|
||||
const effectiveSubTags = hasSubRating ? subTags : [...parentRatingTags, ...subTags];
|
||||
|
||||
const subIsNsfl = cfg.enable_nsfl && effectiveSubTags.some(t => t.id == nsfl_id || t.normalized === 'nsfl');
|
||||
const subIsNsfw = effectiveSubTags.some(t => t.id == 2);
|
||||
const subIsSfw = effectiveSubTags.some(t => t.id == 1);
|
||||
const subIsUntagged = !subIsSfw && !subIsNsfw && !subIsNsfl;
|
||||
|
||||
// Excluded tags check
|
||||
if (excludedTags && excludedTags.length > 0 && subTags.length > 0) {
|
||||
if (subTags.some(t => excludedTags.includes(t.normalized) || excludedTags.includes(lib.slugify(t.tag)))) {
|
||||
if (excludedTags && excludedTags.length > 0 && effectiveSubTags.length > 0) {
|
||||
if (effectiveSubTags.some(t => excludedTags.includes(t.normalized) || excludedTags.includes(lib.slugify(t.tag)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1664,10 +1674,16 @@ const f0cklib = {
|
||||
album = await Promise.all(albumRows.map(async (r, idx) => {
|
||||
const order = idx;
|
||||
const subSlug = r.slug || r.id;
|
||||
const isYouTube = r.mime === 'video/youtube';
|
||||
const subBase = r.dest.replace(/\.[^.]+$/, '');
|
||||
const isAudio = (r.mime || '').startsWith('audio/');
|
||||
let subCover = null;
|
||||
let subThumb = `${cfg.websrv.paths.thumbnails}/${subBase}.webp`;
|
||||
// YouTube sub-items: thumbnail is stored by album_item row id (not by filename)
|
||||
let subThumb = isYouTube
|
||||
? `${cfg.websrv.paths.thumbnails}/${r.id}.webp`
|
||||
: `${cfg.websrv.paths.thumbnails}/${subBase}.webp`;
|
||||
// Also try YouTube CDN thumbnail as fallback
|
||||
const ytVideoId = isYouTube ? r.dest.replace('yt:', '') : null;
|
||||
|
||||
if (isAudio) {
|
||||
const caFile = path.join(cfg.paths.ca, `${subBase}.webp`);
|
||||
@@ -1729,13 +1745,15 @@ const f0cklib = {
|
||||
}
|
||||
|
||||
let subTags = tagsBySubId.get(r.id) || [];
|
||||
const hasSubRating = subTags.some(t => t.id == 1 || t.id == 2 || (cfg.enable_nsfl && (t.id == nsfl_id || t.normalized === 'nsfl')));
|
||||
const combinedSubTags = hasSubRating ? subTags : [...parentRatingTags, ...subTags];
|
||||
|
||||
return {
|
||||
id: r.id,
|
||||
slug: r.slug,
|
||||
subf0ck_id: subSlug,
|
||||
dest: `${cfg.websrv.paths.images}/${r.dest}`,
|
||||
src: `${cfg.websrv.paths.images}/${r.dest}`,
|
||||
dest: isYouTube ? r.dest : `${cfg.websrv.paths.images}/${r.dest}`,
|
||||
src: isYouTube ? `https://www.youtube.com/embed/${ytVideoId}?enablejsapi=1` : `${cfg.websrv.paths.images}/${r.dest}`,
|
||||
filename: r.dest,
|
||||
mime: r.mime,
|
||||
size: lib.formatSize(subSizeNum),
|
||||
@@ -1746,12 +1764,16 @@ const f0cklib = {
|
||||
display_index: order + 1,
|
||||
is_first: order === 0,
|
||||
is_video: (r.mime || '').startsWith('video/'),
|
||||
is_youtube: isYouTube,
|
||||
is_audio: isAudio,
|
||||
is_image: (r.mime || '').startsWith('image/'),
|
||||
has_coverart: isAudio ? !!subCover : false,
|
||||
coverart: isAudio ? subCover : null,
|
||||
thumb: subThumb,
|
||||
tags: subTags
|
||||
// Use YouTube CDN thumb as fallback for strip thumbnails
|
||||
thumb: isYouTube
|
||||
? `https://img.youtube.com/vi/${ytVideoId}/mqdefault.jpg`
|
||||
: subThumb,
|
||||
tags: combinedSubTags
|
||||
};
|
||||
}));
|
||||
|
||||
@@ -1797,11 +1819,12 @@ const f0cklib = {
|
||||
actitem.coverart = targetSub.coverart;
|
||||
}
|
||||
if (targetSub.tags && targetSub.tags.length > 0) {
|
||||
effectiveItemTags = targetSub.tags;
|
||||
const hasSubRating = targetSub.tags.some(t => t.id == 1 || t.id == 2 || (cfg.enable_nsfl && (t.id == nsfl_id || t.normalized === 'nsfl')));
|
||||
effectiveItemTags = hasSubRating ? targetSub.tags : [...parentRatingTags, ...targetSub.tags];
|
||||
} else if (reqIdx === 0) {
|
||||
effectiveItemTags = tags;
|
||||
} else {
|
||||
effectiveItemTags = [];
|
||||
effectiveItemTags = [...parentRatingTags];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1944,7 +1967,7 @@ const f0cklib = {
|
||||
})(),
|
||||
// og_description: include rating + uploader for bots (Matrix, Discord, etc.)
|
||||
og_description: (() => {
|
||||
const ratingLabel = isNsfl ? 'NSFL' : (isNsfw ? 'NSFW' : (isSfw ? 'SFW' : 'Untagged'));
|
||||
const ratingLabel = isNsfl ? 'NSFL' : (isNsfw ? 'NSFW' : (isSfw ? 'SFW' : 'Unrated'));
|
||||
const titlePart = actitem.title ? ` · "${actitem.title}"` : '';
|
||||
return `${ratingLabel}${titlePart} · uploaded by ${actitem.username}`;
|
||||
})(),
|
||||
@@ -2012,7 +2035,8 @@ const f0cklib = {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
const user = rawUser ? lib.escapeLike(decodeURI(rawUser)) : null;
|
||||
const user = rawUser ? decodeURI(rawUser) : null;
|
||||
const userLike = user ? lib.escapeLike(user) : null;
|
||||
const hall = rawHall || null;
|
||||
|
||||
// --- title: prefix — search items.title instead of the tags table ---
|
||||
@@ -2079,7 +2103,7 @@ const f0cklib = {
|
||||
left join tags on tags.id = tags_assign.tag_id
|
||||
where
|
||||
${db.unsafe(modequery)}
|
||||
and "user".user ilike ${user}
|
||||
and "user".user ilike ${userLike}
|
||||
and items.active = true
|
||||
and coalesce(items.visibility, 0) = 0
|
||||
${mimeSQL}
|
||||
@@ -2121,7 +2145,7 @@ const f0cklib = {
|
||||
and items.active = true
|
||||
and coalesce(items.visibility, 0) = 0
|
||||
${tagFilter}
|
||||
${user ? db`and items.username ilike ${user}` : db``}
|
||||
${user ? db`and items.username ilike ${userLike}` : db``}
|
||||
${hall ? db`and items.id in (select item_id from halls_assign ha join halls h on h.id = ha.hall_id where h.slug = ${hall})` : db``}
|
||||
${mimeSQL}
|
||||
${(!session || isAnonSession(session)) && getGlobalfilter(session) ? db`and not exists (select 1 from tags_assign where item_id = items.id and (${db.unsafe(getGlobalfilter(session))}))` : db``}
|
||||
@@ -2223,7 +2247,8 @@ const f0cklib = {
|
||||
return { items: [], total: 0 };
|
||||
}
|
||||
}
|
||||
const user = rawUser ? lib.escapeLike(decodeURI(rawUser)) : null;
|
||||
const user = rawUser ? decodeURI(rawUser) : null;
|
||||
const userLike = user ? lib.escapeLike(user) : null;
|
||||
const hall = rawHall || null;
|
||||
|
||||
const _decodedTag = rawTag ? decodeURIComponent(rawTag) : '';
|
||||
@@ -2277,7 +2302,7 @@ const f0cklib = {
|
||||
INNER JOIN items ON favorites.item_id = items.id
|
||||
INNER JOIN "user" ON "user".id = favorites.user_id
|
||||
WHERE ${db.unsafe(modequery)}
|
||||
AND "user".user ILIKE ${user}
|
||||
AND "user".user ILIKE ${userLike}
|
||||
AND items.active = true AND coalesce(items.visibility, 0) = 0
|
||||
${mimeSQL} ${globalFilter}
|
||||
ORDER BY items.id
|
||||
@@ -2310,7 +2335,7 @@ const f0cklib = {
|
||||
WHERE ${db.unsafe(modequery)}
|
||||
AND items.active = true AND coalesce(items.visibility, 0) = 0
|
||||
${tagFilter}
|
||||
${user ? db`and items.username ilike ${user}` : db``}
|
||||
${user ? db`and items.username ilike ${userLike}` : db``}
|
||||
${hall ? db`and items.id in (select item_id from halls_assign ha join halls h on h.id = ha.hall_id where h.slug = ${hall})` : db``}
|
||||
${mimeSQL} ${globalFilter} ${excludeFilter}
|
||||
ORDER BY items.id
|
||||
|
||||
Reference in New Issue
Block a user