|
@@ -269,7 +269,8 @@ function buildMeta(
|
|
|
pj: ProjectJson | null,
|
|
pj: ProjectJson | null,
|
|
|
existing?: WallpaperMeta,
|
|
existing?: WallpaperMeta,
|
|
|
workshopTimeUpdated?: number,
|
|
workshopTimeUpdated?: number,
|
|
|
- authorSteamId?: string
|
|
|
|
|
|
|
+ authorSteamId?: string,
|
|
|
|
|
+ liveWorkshopTags?: string[]
|
|
|
): WallpaperMeta {
|
|
): WallpaperMeta {
|
|
|
const now = Date.now()
|
|
const now = Date.now()
|
|
|
const { downloading: _d, downloadFailed: _df, ...existingRest } = existing ?? { appliedCount: 0, categories: [] }
|
|
const { downloading: _d, downloadFailed: _df, ...existingRest } = existing ?? { appliedCount: 0, categories: [] }
|
|
@@ -280,12 +281,17 @@ function buildMeta(
|
|
|
// it unset here falls back to the "No preview" placeholder, and the next
|
|
// it unset here falls back to the "No preview" placeholder, and the next
|
|
|
// library scan picks up the real file once it exists.
|
|
// library scan picks up the real file once it exists.
|
|
|
const previewPath = pj?.preview ? path.join(localPath, pj.preview) : undefined
|
|
const previewPath = pj?.preview ? path.join(localPath, pj.preview) : undefined
|
|
|
|
|
+ // Steam can flag an item Mature after the fact (moderation, community reports) without the
|
|
|
|
|
+ // author ever republishing - project.json keeps saying whatever it said at publish time, so
|
|
|
|
|
+ // the live Workshop tags are the only place that catches it.
|
|
|
|
|
+ const fromProject = stricterRating(normalizeRating(pj?.contentrating), deriveRatingFromTags(pj?.tags ?? []))
|
|
|
|
|
+ const contentRating = stricterRating(fromProject, deriveRatingFromTags(liveWorkshopTags ?? []))
|
|
|
return {
|
|
return {
|
|
|
...existingRest,
|
|
...existingRest,
|
|
|
id: workshopId,
|
|
id: workshopId,
|
|
|
title: pj?.title ?? `Wallpaper ${workshopId}`,
|
|
title: pj?.title ?? `Wallpaper ${workshopId}`,
|
|
|
type: normalizeType(pj?.type),
|
|
type: normalizeType(pj?.type),
|
|
|
- contentRating: stricterRating(normalizeRating(pj?.contentrating), deriveRatingFromTags(pj?.tags ?? [])),
|
|
|
|
|
|
|
+ contentRating,
|
|
|
description: pj?.description,
|
|
description: pj?.description,
|
|
|
previewLocal: previewPath && fs.existsSync(previewPath) ? previewPath : undefined,
|
|
previewLocal: previewPath && fs.existsSync(previewPath) ? previewPath : undefined,
|
|
|
previewUrl: undefined,
|
|
previewUrl: undefined,
|
|
@@ -459,6 +465,10 @@ export async function scanLibrary(): Promise<{ imported: number; skipped: number
|
|
|
...toRebuild.map(({ entry }) => entry.name),
|
|
...toRebuild.map(({ entry }) => entry.name),
|
|
|
...cacheHits
|
|
...cacheHits
|
|
|
])
|
|
])
|
|
|
|
|
+ const liveTags = await safeGetWorkshopTags([
|
|
|
|
|
+ ...toRebuild.map(({ entry }) => entry.name),
|
|
|
|
|
+ ...cacheHits
|
|
|
|
|
+ ])
|
|
|
|
|
|
|
|
for (const { entry, localPath, pj } of toRebuild) {
|
|
for (const { entry, localPath, pj } of toRebuild) {
|
|
|
wallpapers[entry.name] = buildMeta(
|
|
wallpapers[entry.name] = buildMeta(
|
|
@@ -467,7 +477,8 @@ export async function scanLibrary(): Promise<{ imported: number; skipped: number
|
|
|
pj,
|
|
pj,
|
|
|
wallpapers[entry.name] ?? undefined,
|
|
wallpapers[entry.name] ?? undefined,
|
|
|
timesUpdated.get(entry.name),
|
|
timesUpdated.get(entry.name),
|
|
|
- authors.get(entry.name)
|
|
|
|
|
|
|
+ authors.get(entry.name),
|
|
|
|
|
+ liveTags.get(entry.name)
|
|
|
)
|
|
)
|
|
|
imported++
|
|
imported++
|
|
|
}
|
|
}
|
|
@@ -476,6 +487,7 @@ export async function scanLibrary(): Promise<{ imported: number; skipped: number
|
|
|
for (const id of cacheHits) {
|
|
for (const id of cacheHits) {
|
|
|
const seconds = timesUpdated.get(id)
|
|
const seconds = timesUpdated.get(id)
|
|
|
const authorId = authors.get(id)
|
|
const authorId = authors.get(id)
|
|
|
|
|
+ const live = liveTags.get(id)
|
|
|
|
|
|
|
|
// A time_updated bump means the author changed something on the Workshop side
|
|
// A time_updated bump means the author changed something on the Workshop side
|
|
|
// (tags, content rating, a republish) - re-read project.json instead of just
|
|
// (tags, content rating, a republish) - re-read project.json instead of just
|
|
@@ -491,7 +503,8 @@ export async function scanLibrary(): Promise<{ imported: number; skipped: number
|
|
|
pj,
|
|
pj,
|
|
|
wallpapers[id],
|
|
wallpapers[id],
|
|
|
seconds,
|
|
seconds,
|
|
|
- authorId ?? wallpapers[id].authorSteamId
|
|
|
|
|
|
|
+ authorId ?? wallpapers[id].authorSteamId,
|
|
|
|
|
+ live
|
|
|
)
|
|
)
|
|
|
resynced = true
|
|
resynced = true
|
|
|
continue
|
|
continue
|
|
@@ -505,6 +518,14 @@ export async function scanLibrary(): Promise<{ imported: number; skipped: number
|
|
|
if (authorId && wallpapers[id].authorSteamId !== authorId) {
|
|
if (authorId && wallpapers[id].authorSteamId !== authorId) {
|
|
|
patch.authorSteamId = authorId
|
|
patch.authorSteamId = authorId
|
|
|
}
|
|
}
|
|
|
|
|
+ // Only tighten, never loosen - a failed/empty tag fetch must not walk a rating back down.
|
|
|
|
|
+ const liveRating = live ? deriveRatingFromTags(live) : undefined
|
|
|
|
|
+ if (liveRating) {
|
|
|
|
|
+ const stricter = stricterRating(wallpapers[id].contentRating ?? 'uncategorized', liveRating)
|
|
|
|
|
+ if (stricter !== wallpapers[id].contentRating) {
|
|
|
|
|
+ patch.contentRating = stricter
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
if (Object.keys(patch).length > 0) {
|
|
if (Object.keys(patch).length > 0) {
|
|
|
wallpapers[id] = { ...wallpapers[id], ...patch }
|
|
wallpapers[id] = { ...wallpapers[id], ...patch }
|
|
|
resynced = true
|
|
resynced = true
|