Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci-patched.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
name: Patched checks
# Never runs outside the fork: if this file ever reaches upstream by a bad
# merge, it stays silent there instead of double-running their CI.
if: github.repository == 'codeon89/Atlas'
if: github.repository == 'codeon89/Atlas-Patched'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/nightly-patched.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
# This file must never publish from anywhere else: not from a fork of this
# fork, not from a feature branch. Downstream jobs cascade-skip when this
# one does, so guarding here covers the whole workflow.
if: github.repository == 'codeon89/Atlas' && github.ref == 'refs/heads/nightly-patched'
if: github.repository == 'codeon89/Atlas-Patched' && github.ref == 'refs/heads/nightly-patched'
runs-on: ubuntu-latest
timeout-minutes: 20
outputs:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr-policy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name: PR Policy
# the heavier CI job so contributors find out about a wrong base branch in
# seconds rather than after a fifteen-minute build.
#
# Fork divergence (codeon89/Atlas): Rule 1 also accepts `nightly-patched`
# Fork divergence (codeon89/Atlas-Patched): Rule 1 also accepts `nightly-patched`
# (the fork's integration branch); changelog and AI-disclosure rules are not
# enforced. Review upstream changes to this file on every merge-down.

Expand Down
9 changes: 6 additions & 3 deletions CHANGELOG.PATCHED.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
# CHANGELOG - PATCHED

**v0.9.9-patched.nightly.494.3**
- Importer and Library folder scheme now support `{atlasId}`, so installs can be matched back to AtlasDB on re-import / rebuild.[#404](https://github.com/towerwatchman/Atlas/pull/404)

**v0.9.9-patched.nightly.494.2**
- Removed the stale restart popup and hint on the Show debug console toggle — it applies immediately to all open windows.[#399](https://github.com/towerwatchman/Atlas/pull/399)
- (Dev-Only) DevTools no longer auto-opens in dev mode unless explicitly enabled in config.
- Nightly-Patched: support Linux builds & patch ci runs. [#20](https://github.com/codeon89/Atlas/pull/20)
- Nightly-Patched: support Linux builds & patch ci runs. [#20](https://github.com/codeon89/Atlas-Patched/pull/20)

**v0.9.9-patched.nightly.494.1**
- Update debounce logic for Browse and Library: Search in Catalog Browse and Library now debounces the text input and waits for a pause before filtering. Previously every keystroke updated `activeFilters.text` and ran `filterGamesWithState` (Library) or scheduled a catalog fetch, causing input lag on large libraries and a wasted local-filter pass even while browsing the server-side catalog. The input still echoes instantly from local state; clear bypasses the delay.[#398](https://github.com/towerwatchman/Atlas/pull/398)
- LewdCorner member tier detection. Atlas now scrapes your LewdCorner account's shop page to determine your membership tier (Standard / Plus) and stores it alongside your credentials. Browse filters content by tier so Plus users see everything while Standard or non-login users only see what their subscription allows.[#391](https://github.com/towerwatchman/Atlas/pull/391)
- Support `[no-build]` detection in your HEAD commit message when pushing without wanting a release (docs or changelog-only pushes) or merge existing change from original Atlas.[#19](https://github.com/codeon89/Atlas/pull/19)
- Nightly-Patched releases: the fork ships its own Windows + Linux installer line (`{base}-patched.nightly.{nightly}.{p}`) with a third update channel under Settings > App Updates. Patched builds check only the fork feed; upstream nightlies surface as a read-only notice, never a download. See `docs/FORK-PATCHED-RUNBOOK.md`.[#19](https://github.com/codeon89/Atlas/pull/19)
- Support `[no-build]` detection in your HEAD commit message when pushing without wanting a release (docs or changelog-only pushes) or merge existing change from original Atlas.[#19](https://github.com/codeon89/Atlas-Patched/pull/19)
- Nightly-Patched releases: the fork ships its own Windows + Linux installer line (`{base}-patched.nightly.{nightly}.{p}`) with a third update channel under Settings > App Updates. Patched builds check only the fork feed; upstream nightlies surface as a read-only notice, never a download. See `docs/FORK-PATCHED-RUNBOOK.md`.[#19](https://github.com/codeon89/Atlas-Patched/pull/19)


**Previously merged before packaging**
Expand Down
1 change: 0 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
- Path resolution highlighting: red if invalid, green if path exists or pass the check.

### Added
- LewdCorner member tier detection. Atlas now scrapes your LewdCorner account's shop page to determine your membership tier (Standard / Plus / non-logged in) and stores it alongside your credentials. Browse filters content by tier so Plus users see everything while Standard or non-login users only see what their subscription allows. Tier is shown immediately on first connect, rechecked periodically (configurable via `lcTierRecheckHours`), and forced on re-link. A dev-only console warning fires when the scraped tier disagrees with the stored value. (`electron/accounts/xenforoAuth.js`, `electron/accounts/accountStore.js`, `electron/db/catalogIndex.js`, `src/components/settings/Accounts.jsx`)
- Custom media uploads in the Game Details Media tab: add preview images from local files, a drag-and-drop zone, or an image URL, with live progress. Previews can be reordered by drag and the order persists in a new `preview_sort` table keyed by remote URL (or relative path for custom uploads), so it survives re-downloads, stream/download switches and metadata refreshes. Previews now carry a source logo and a storage-location badge, and custom previews can be deleted independently of downloaded ones.
- Add Buzzheavier host support (`buzzheavier.com`, `bzzhr.to`, `bzzhr.co`). The download route is behind a Cloudflare challenge, so the resolve runs in a browser window: it clicks the htmx download button, captures the `HX-Redirect` (or an attachment via `will-download`), and hands the resolved CDN link plus the browser's own cookies/UA back to the downloader. The resolve partition is persistent so a solved challenge survives a restart -- only Cloudflare's own challenge cookies are kept, everything else is stripped after each resolve -- and resolves run one at a time, since a shared session cannot carry two concurrently. Each time your IP changes there is a brief auto-resolve window while the challenge is re-solved.
- The version readout in the topnav and sidebar is now a button that opens that version's GitHub release page. The tag it builds matches what the release workflows publish -- `v<version>` for stable and `v<version>-nightly.<run>` for nightly -- so it lands on the real release rather than a 404. (#143)
Expand Down
7 changes: 4 additions & 3 deletions PATCHES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Pending Patched Changes
*Changes that's already on the fork and waiting to be reviewed for merge into original Atlas*
- Importer and Library folder scheme now support `{atlasId}`, so installs can be matched back to AtlasDB on re-import / rebuild.[#404](https://github.com/towerwatchman/Atlas/pull/404)
- Removed the stale restart popup and hint on the Show debug console toggle — it applies immediately to all open windows.[#399](https://github.com/towerwatchman/Atlas/pull/399)
- (Dev-Only) DevTools no longer auto-opens in dev mode unless explicitly enabled in config.
- Update debounce logic for Browse and Library: Search in Catalog Browse and Library now debounces the text input and waits for a pause before filtering. Previously every keystroke updated `activeFilters.text` and ran `filterGamesWithState` (Library) or scheduled a catalog fetch, causing input lag on large libraries and a wasted local-filter pass even while browsing the server-side catalog. The input still echoes instantly from local state; clear bypasses the delay.[#398](https://github.com/towerwatchman/Atlas/pull/398)
Expand All @@ -13,9 +14,9 @@

## Fork's System Change
*internal change that's not features but backend requirement for forks to release self-builds*
- Support Linux builds & patch ci runs. [#20](https://github.com/codeon89/Atlas/pull/20)
- Support `[no-build]` detection in your HEAD commit message when pushing without wanting a release (docs or changelog-only pushes) or merge existing change from original Atlas.[#19](https://github.com/codeon89/Atlas/pull/19)
- Nightly-Patched releases: the fork ships its own Windows + Linux installer line (`{base}-patched.nightly.{nightly}.{p}`) with a third update channel under Settings > App Updates. Patched builds check only the fork feed; upstream nightlies surface as a read-only notice, never a download. See `docs/FORK-PATCHED-RUNBOOK.md`. [#19](https://github.com/codeon89/Atlas/pull/19)
- Support Linux builds & patch ci runs. [#20](https://github.com/codeon89/Atlas-Patched/pull/20)
- Support `[no-build]` detection in your HEAD commit message when pushing without wanting a release (docs or changelog-only pushes) or merge existing change from original Atlas.[#19](https://github.com/codeon89/Atlas-Patched/pull/19)
- Nightly-Patched releases: the fork ships its own Windows + Linux installer line (`{base}-patched.nightly.{nightly}.{p}`) with a third update channel under Settings > App Updates. Patched builds check only the fork feed; upstream nightlies surface as a read-only notice, never a download. See `docs/FORK-PATCHED-RUNBOOK.md`. [#19](https://github.com/codeon89/Atlas-Patched/pull/19)


## Merged to thetowerman/Atlas's Nightly
Expand Down
2 changes: 1 addition & 1 deletion docs/FORK-PATCHED-RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Nightly-Patched releases (codeon89/Atlas)
# Nightly-Patched releases (codeon89/Atlas-Patched)

Plain-language reference for the fork's own release line. Procedures live in
`docs/FORK-PATCHED-RUNBOOK.md`.
Expand Down
2 changes: 1 addition & 1 deletion docs/FORK-PATCHED-RUNBOOK.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Nightly-Patched runbook (codeon89/Atlas)
# Nightly-Patched runbook (codeon89/Atlas-Patched)

Evergreen fork-only operations. Plain-language overview:
`docs/FORK-PATCHED-RELEASES.md`.
Expand Down
1 change: 1 addition & 0 deletions electron/ipc/importer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4771,6 +4771,7 @@ ipcMain.handle("downloads-install", async (event, { id, version, onComplete, kee
currentConfig?.Library?.libraryFolderStructure,
{
f95Id: record.f95_id || record.f95Id || "",
atlasId: record.atlas_id || record.atlasId || "",
engine: record.engine || "Unknown",
creator: record.creator,
title: record.title,
Expand Down
1 change: 1 addition & 0 deletions electron/library/importRules.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ function buildStructuredImportPath(targetLibrary, format, game) {
if (key === "version") return normalizeVersionName(game.version);
if (key === "engine") return game.engine || "Unknown";
if (key === "f95id") return game.f95Id || "Unknown";
if (key === "atlasid") return game.atlasId || game.atlas_id || "Unknown";
if (key === "lcid" || key === "lewdcornerid") return game.lcId || game.lewdCornerId || "Unknown";
return "Unknown";
}),
Expand Down
2 changes: 1 addition & 1 deletion electron/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ function configureAppUpdateBranch(branch, { resetStatus = false } = {}) {
// upstream. A fork build pointed at upstream would offer to replace itself
// with an official build that lacks the fork feed entirely.
owner: normalizedBranch === 'patched' ? 'codeon89' : 'towerwatchman',
repo: 'Atlas',
repo: normalizedBranch === 'patched' ? 'Atlas-Patched' : 'Atlas',
channel,
})

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
"publish": {
"provider": "github",
"owner": "codeon89",
"repo": "Atlas",
"repo": "Atlas-Patched",
"releaseType": "draft",
"channel": "patched",
"vPrefixedTagName": true
Expand Down
2 changes: 1 addition & 1 deletion scripts/build-patched.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ async function run() {
// Deliberately explicit: neither an inherited upstream config nor a new
// remote can redirect a personal publish into someone else's repository.
publish: {
provider: 'github', owner: 'codeon89', repo: 'Atlas', channel: 'patched',
provider: 'github', owner: 'codeon89', repo: 'Atlas-Patched', channel: 'patched',
releaseType: 'draft', vPrefixedTagName: true,
},
},
Expand Down
3 changes: 2 additions & 1 deletion src/components/downloads/LibraryStructureModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ const previewPath = (pattern) =>
.replace(/\{title\}/g, SAMPLE.title)
.replace(/\{version\}/g, SAMPLE.version)
.replace(/\{engine\}/g, 'RenPy')
.replace(/\{f95Id\}/g, '12345'),
.replace(/\{f95Id\}/g, '12345')
.replace(/\{atlasId\}/g, '6789'),
)
.filter(Boolean)

Expand Down
1 change: 1 addition & 0 deletions src/components/importer/Importer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,7 @@ const Importer = () => {
engine: groups.engine || '',
f95Id: groups.f95id || '',
lcId: groups.lcid || '',
atlasId: groups.atlasid || '',
}
if (!cancelled) {
setLivePreview({
Expand Down
4 changes: 3 additions & 1 deletion src/components/importer/steps/SettingsStep.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default function SettingsStep({
{ label: 'Creator / Title - Version', value: '{creator}/{title} - {version}' },
{ label: 'Title / Version, Creator', value: '{title}/{version},{creator}' },
{ label: 'F95 ID / Title / Version', value: '{f95Id}/{title}/{version}' },
{ label: 'Atlas ID / Title / Version', value: '{atlasId}/{title}/{version}' },
{ label: 'LewdCorner ID / Title / Version', value: '{lcId}/{title}/{version}' },
]
// "Auto detect" (unstructured name guessing) has been removed for now, so the
Expand Down Expand Up @@ -167,6 +168,7 @@ export default function SettingsStep({
['Engine', livePreview.fields.engine, false],
['F95 ID', livePreview.fields.f95Id, false],
['LC ID', livePreview.fields.lcId, false],
['Atlas ID', livePreview.fields.atlasId, false],
].filter(([, value, always]) => always || value).map(([label, value]) => (
<div key={label} className="min-w-0">
<div className="text-[11px] uppercase tracking-wide text-muted">{label}</div>
Expand Down Expand Up @@ -221,7 +223,7 @@ export default function SettingsStep({
onChange={(e) => setLibraryFormat(e.target.value)}
spellCheck={false}
placeholder="{creator}/{title}/{version}"
title="Destination path template. Tokens: {creator} {title} {version} {f95Id} {lcId}"
title="Destination path template. Tokens: {creator} {title} {version} {f95Id} {lcId} {atlasId}"
className="sm:ml-2 flex-1 min-w-0 bg-secondary text-text border border-border rounded-buttonTheme p-1 focus:outline-none focus:ring-1 focus:ring-accent font-mono text-xs"
/>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/settings/Library.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ const Library = () => {
<p className="text-xs opacity-60 mt-1">
Used when imports are moved or archives are extracted into the default
library folder. Options: {"{creator}"}, {"{title}"}, {"{version}"},{" "}
{"{engine}"}, {"{f95Id}"}.
{"{engine}"}, {"{f95Id}"}, {"{atlasId}"}.
<br />
Example: {"{f95Id}/{creator}/{title}/{version}"}
</p>
Expand Down
2 changes: 1 addition & 1 deletion src/utils/releaseUrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ import { LINKS } from './links.js'
*/
export function releaseUrlFor(version) {
const tag = String(version ?? '').trim().replace(/^v+/i, '')
const repo = tag.includes('-patched.') ? 'https://github.com/codeon89/Atlas' : LINKS.github
const repo = tag.includes('-patched.') ? 'https://github.com/codeon89/Atlas-Patched' : LINKS.github
return `${repo}/releases/tag/v${tag}`
}
13 changes: 12 additions & 1 deletion tests/importer-helpers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,17 @@ describe('buildStructuredImportPath', () => {
const out = T.buildStructuredImportPath('/lib', '{lcid}', { lcId: 'LC9' })
expect(out).toBe(path.join('/lib', 'LC9'))
})

it('supports atlasid from camelCase or snake_case, any casing', () => {
expect(T.buildStructuredImportPath('/lib', '{atlasId}', { atlasId: '456' })).toBe(path.join('/lib', '456'))
expect(T.buildStructuredImportPath('/lib', '{atlasId}', { atlas_id: 456 })).toBe(path.join('/lib', '456'))
expect(T.buildStructuredImportPath('/lib', '{AtlasID}', { atlasId: '456' })).toBe(path.join('/lib', '456'))
})

it('falls back to Unknown for a missing atlas id, even mid-segment', () => {
const out = T.buildStructuredImportPath('/lib', '{title} [{atlasId}]/{version}', { title: 'My Game', version: '1.0' })
expect(out).toBe(path.join('/lib', 'My Game [Unknown]', '1.0'))
})
})


Expand Down Expand Up @@ -121,7 +132,7 @@ test('downloads-install passes required fields in buildStructuredImportPath', ()
if (!obj) throw new Error('buildStructuredImportPath was not given an object literal')

const keys = obj.properties.map((p) => p.key.name)
const required = ['f95Id', 'engine', 'creator', 'title', 'version']
const required = ['f95Id', 'atlasId', 'engine', 'creator', 'title', 'version']

for (const key of required) {
expect(keys).toContain(key)
Expand Down
2 changes: 1 addition & 1 deletion tests/patched-ci-workflow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const upstream = fs.readFileSync(path.join(here, '../.github/workflows/ci.yml'),

describe('ci-patched workflow', () => {
it('runs only in the fork repo', () => {
expect(workflow).toContain("github.repository == 'codeon89/Atlas'")
expect(workflow).toContain("github.repository == 'codeon89/Atlas-Patched'")
})

it('restores node_modules and skips reinstall on a hit', () => {
Expand Down
2 changes: 1 addition & 1 deletion tests/patched-release-workflow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const workflow = fs.readFileSync(path.join(here, '../.github/workflows/nightly-p
describe('nightly-patched release workflow', () => {
it('fires only on the fork branch and only in the fork repo', () => {
expect(workflow).toContain('branches: [nightly-patched]')
expect(workflow).toContain("github.repository == 'codeon89/Atlas' && github.ref == 'refs/heads/nightly-patched'")
expect(workflow).toContain("github.repository == 'codeon89/Atlas-Patched' && github.ref == 'refs/heads/nightly-patched'")
})

it('queues runs instead of cancelling (no duplicate release numbers)', () => {
Expand Down
3 changes: 2 additions & 1 deletion tests/patched-updates.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ describe('patched update channel', () => {
])('routes %s to its own feed and installed-version baseline', (branch, owner, channel, prerelease, baseline) => {
const ctx = updaterContext()
ctx.configureAppUpdateBranch(branch)
expect(ctx.autoUpdater.setFeedURL).toHaveBeenCalledWith({ provider: 'github', owner, repo: 'Atlas', channel })
const repo = branch === 'patched' ? 'Atlas-Patched' : 'Atlas'
expect(ctx.autoUpdater.setFeedURL).toHaveBeenCalledWith({ provider: 'github', owner, repo, channel })
expect(ctx.autoUpdater.channel).toBe(channel)
expect(ctx.autoUpdater.allowPrerelease).toBe(prerelease)
expect(ctx.autoUpdater.allowDowngrade).toBe(false)
Expand Down
2 changes: 1 addition & 1 deletion tests/release-url.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ describe('releaseUrlFor', () => {
// even when the user currently follows an official channel.
it('points patched builds at the fork releases', () => {
expect(releaseUrlFor('0.9.9-patched.nightly.494.1')).toBe(
'https://github.com/codeon89/Atlas/releases/tag/v0.9.9-patched.nightly.494.1'
'https://github.com/codeon89/Atlas-Patched/releases/tag/v0.9.9-patched.nightly.494.1'
)
})
})
Loading