diff --git a/apps/api/app/admin/softwares.rb b/apps/api/app/admin/softwares.rb
index e80a657..94ec875 100644
--- a/apps/api/app/admin/softwares.rb
+++ b/apps/api/app/admin/softwares.rb
@@ -3,7 +3,7 @@ ActiveAdmin.register Software do
:license, :platform, :status, :highlighted,
software_images_attributes: [ :id, :image_id, :is_default, :position, :file_upload, :_destroy ],
external_links_attributes: [ :id, :label, :url, :_destroy ],
- releases_attributes: [ :id, :version, :web_playable, :_destroy,
+ releases_attributes: [ :id, :version, :_destroy,
{ release_assets_attributes: [ :id, :kind, :path, :_destroy ] } ]
menu priority: 2, label: "🎮 Softwares"
@@ -127,7 +127,6 @@ ActiveAdmin.register Software do
f.inputs "Releases" do
f.has_many :releases, allow_destroy: true, new_record: true do |r|
r.input :version
- r.input :web_playable
r.has_many :release_assets, allow_destroy: true, new_record: true do |ra|
ra.input :kind, as: :select, collection: ReleaseAsset::KINDS, include_blank: false
ra.input :path
diff --git a/apps/api/app/models/release.rb b/apps/api/app/models/release.rb
index 8eeac44..5ec553f 100644
--- a/apps/api/app/models/release.rb
+++ b/apps/api/app/models/release.rb
@@ -18,13 +18,13 @@ class Release < ApplicationRecord
return unless software&.platform == "c64"
has_html = release_assets.reject(&:marked_for_destruction?).any? { |a| a.kind == "html" }
- if has_html || web_playable?
+ if has_html
errors.add(:base, "C64 releases cannot be web playable (download only)")
end
end
def self.ransackable_attributes(auth_object = nil)
- %w[created_at deleted_at id software_id updated_at version web_playable]
+ %w[created_at deleted_at id software_id updated_at version]
end
def self.ransackable_associations(auth_object = nil)
diff --git a/apps/api/app/services/software_response_builder.rb b/apps/api/app/services/software_response_builder.rb
index 7c673de..d8da64d 100644
--- a/apps/api/app/services/software_response_builder.rb
+++ b/apps/api/app/services/software_response_builder.rb
@@ -2,9 +2,10 @@ module SoftwareResponseBuilder
private
def build_response(software, releases)
- sorted = releases.sort_by { |r| r.created_at || Time.at(0) }.reverse
- latest = sorted.reject { |r| r.version.to_s.start_with?("dev-") }.first
- web_playable = sorted.find { |r| r.release_assets.any? { |a| a.kind == "html" } }
+ sorted = releases.sort_by { |r| r.created_at || Time.at(0) }.reverse
+ latest = sorted.reject { |r| r.version.to_s.start_with?("dev-") }.first
+ # web-playable, ha az utolsó (stabil) release-nek van webes assetje
+ web_playable = latest if latest&.release_assets&.any? { |a| a.kind == "html" }
total_downloads = releases.sum { |r| r.association(:downloads).loaded? ? r.downloads.size : 0 }
SoftwareDetailSerializer.render_as_hash(software,
diff --git a/apps/api/db/migrate/20260802000003_remove_web_playable_from_releases.rb b/apps/api/db/migrate/20260802000003_remove_web_playable_from_releases.rb
new file mode 100644
index 0000000..acebf35
--- /dev/null
+++ b/apps/api/db/migrate/20260802000003_remove_web_playable_from_releases.rb
@@ -0,0 +1,5 @@
+class RemoveWebPlayableFromReleases < ActiveRecord::Migration[8.1]
+ def change
+ remove_column :releases, :web_playable, :boolean, default: false
+ end
+end
diff --git a/apps/api/db/schema.rb b/apps/api/db/schema.rb
index 88353f7..01bc6e1 100644
--- a/apps/api/db/schema.rb
+++ b/apps/api/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[8.1].define(version: 2026_08_02_000002) do
+ActiveRecord::Schema[8.1].define(version: 2026_08_02_000003) do
create_table "admin_users", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.datetime "created_at", null: false
t.string "email", default: "", null: false
@@ -188,7 +188,6 @@ ActiveRecord::Schema[8.1].define(version: 2026_08_02_000002) do
t.bigint "software_id", unsigned: true
t.datetime "updated_at", precision: 3
t.string "version", limit: 64
- t.boolean "web_playable", default: false
t.index ["deleted_at"], name: "idx_releases_deleted_at"
t.index ["software_id"], name: "idx_releases_software_id"
end
diff --git a/apps/frontend/src/i18n/locales/en.ts b/apps/frontend/src/i18n/locales/en.ts
index d68ec08..2f8a7e2 100644
--- a/apps/frontend/src/i18n/locales/en.ts
+++ b/apps/frontend/src/i18n/locales/en.ts
@@ -146,8 +146,13 @@ export default {
play: 'â–¶ Play',
downloads: 'downloads',
links: 'Links',
- binariesTitle: 'Download for desktop',
- binary: {
+ assetsTitle: 'Downloads',
+ assetDownload: 'Download',
+ assetOpen: 'Open',
+ assetKind: {
+ cartridge: 'Game file',
+ source: 'Source code',
+ docs: 'Documentation',
win_x86: 'Windows (32-bit)',
win_x64: 'Windows (64-bit)',
linux_x86: 'Linux (32-bit)',
diff --git a/apps/frontend/src/i18n/locales/hu.ts b/apps/frontend/src/i18n/locales/hu.ts
index 0e88e6b..6356e3e 100644
--- a/apps/frontend/src/i18n/locales/hu.ts
+++ b/apps/frontend/src/i18n/locales/hu.ts
@@ -146,8 +146,13 @@ export default {
play: '▶ Játék',
downloads: 'letöltés',
links: 'Linkek',
- binariesTitle: 'Letöltés asztali gépre',
- binary: {
+ assetsTitle: 'Letöltések',
+ assetDownload: 'Letöltés',
+ assetOpen: 'Megnyitás',
+ assetKind: {
+ cartridge: 'Játékfájl',
+ source: 'Forráskód',
+ docs: 'Dokumentáció',
win_x86: 'Windows (32 bit)',
win_x64: 'Windows (64 bit)',
linux_x86: 'Linux (32 bit)',
diff --git a/apps/frontend/src/page/catalog/CatalogShowPage.vue b/apps/frontend/src/page/catalog/CatalogShowPage.vue
index 34fa7d7..fc622fd 100644
--- a/apps/frontend/src/page/catalog/CatalogShowPage.vue
+++ b/apps/frontend/src/page/catalog/CatalogShowPage.vue
@@ -92,27 +92,22 @@
{{ t('catalogShow.released') }} {{ formatDateTime(latestStable.UpdatedAt) }}
-
+ {{ t('catalogShow.playNow') }}
-
-
{{ t('catalogShow.binariesTitle') }}
-
+
@@ -137,13 +132,18 @@
{{ release.version }}
↓ {{ release.downloadCount }}
-
+ {{ t('catalogShow.play') }}
+
+
+
+ | {{ t('catalogShow.assetKind.' + asset.kind) }} |
+
+ {{ t('catalogShow.assetOpen') }}
+ {{ t('catalogShow.assetDownload') }}
+ |
+
+
+
{{ formatDateTime(release.UpdatedAt) }} |
@@ -155,11 +155,18 @@
|
{{ release.version }}
-
+ {{ t('catalogShow.play') }}
+
+
+
+ | {{ t('catalogShow.assetKind.' + asset.kind) }} |
+
+ {{ t('catalogShow.assetOpen') }}
+ {{ t('catalogShow.assetDownload') }}
+ |
+
+
+
|
{{ formatDateTime(release.UpdatedAt) }} |
@@ -181,13 +188,18 @@
Dev
-
+ {{ t('catalogShow.play') }}
+
+
+
+ | {{ t('catalogShow.assetKind.' + asset.kind) }} |
+
+ {{ t('catalogShow.assetOpen') }}
+ {{ t('catalogShow.assetDownload') }}
+ |
+
+
+
@@ -265,36 +277,17 @@ const latestStable = computed(() => stableReleases.value[0] ?? null)
const downloadUrl = (path: string) =>
`/api/download?path=${encodeURIComponent(path.replace('/file/', ''))}`
-const BINARY_KINDS = ['win_x64', 'win_x86', 'linux_x64', 'linux_x86', 'mac_universal', 'mac_arm64', 'mac_x64']
+// az asset-táblázat sorai és sorrendjük; a html nem letöltés, azt a Play gomb viszi
+const TABLE_KIND_ORDER = [
+ 'cartridge', 'source', 'docs',
+ 'win_x64', 'win_x86', 'linux_x64', 'linux_x86',
+ 'mac_universal', 'mac_arm64', 'mac_x64',
+]
-// a látogató OS-éhez illő targetek, preferencia-sorrendben
-function osPreferredKinds(): string[] {
- const ua = navigator.userAgent
- if (/Windows/i.test(ua)) {
- return /WOW64|Win64|x64|amd64/i.test(ua) ? ['win_x64', 'win_x86'] : ['win_x86', 'win_x64']
- }
- if (/Macintosh|Mac OS X/i.test(ua)) return ['mac_universal', 'mac_arm64', 'mac_x64']
- if (/Linux/i.test(ua)) return ['linux_x64', 'linux_x86']
- return []
-}
-
-const preferredKinds = osPreferredKinds()
-
-const kindRank = (kind: string) => {
- const preferred = preferredKinds.indexOf(kind)
- return preferred >= 0 ? preferred : preferredKinds.length + BINARY_KINDS.indexOf(kind)
-}
-
-const binaryAssets = (release: Release) =>
+const tableAssets = (release: Release) =>
(release.assets ?? [])
- .filter(a => BINARY_KINDS.includes(a.kind))
- .sort((a, b) => kindRank(a.kind) - kindRank(b.kind))
-
-// a kiemelt gomb: a látogató OS-éhez legjobban illő elérhető bináris
-const primaryBinaryKind = (release: Release) => {
- const first = binaryAssets(release)[0]
- return first && preferredKinds.includes(first.kind) ? first.kind : null
-}
+ .filter(a => TABLE_KIND_ORDER.includes(a.kind))
+ .sort((a, b) => TABLE_KIND_ORDER.indexOf(a.kind) - TABLE_KIND_ORDER.indexOf(b.kind))
onMounted(async () => {
try {