mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 03:39:26 +00:00
Add download
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<groupId>dev.kruhlmann</groupId>
|
<groupId>dev.kruhlmann</groupId>
|
||||||
<artifactId>imgfloat</artifactId>
|
<artifactId>imgfloat</artifactId>
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1</version>
|
||||||
<name>Imgfloat</name>
|
<name>Imgfloat</name>
|
||||||
<description>Livestream overlay with Twitch-authenticated channel admins and broadcasters.</description>
|
<description>Livestream overlay with Twitch-authenticated channel admins and broadcasters.</description>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|||||||
@@ -56,9 +56,10 @@ public class ViewController {
|
|||||||
model.addAttribute("username", sessionUsername);
|
model.addAttribute("username", sessionUsername);
|
||||||
model.addAttribute("channel", sessionUsername);
|
model.addAttribute("channel", sessionUsername);
|
||||||
model.addAttribute("adminChannels", channelDirectoryService.adminChannelsFor(sessionUsername));
|
model.addAttribute("adminChannels", channelDirectoryService.adminChannelsFor(sessionUsername));
|
||||||
|
addVersionAttributes(model);
|
||||||
return "dashboard";
|
return "dashboard";
|
||||||
}
|
}
|
||||||
model.addAttribute("version", versionService.getVersion());
|
addVersionAttributes(model);
|
||||||
return "index";
|
return "index";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,4 +112,9 @@ public class ViewController {
|
|||||||
model.addAttribute("broadcaster", broadcaster.toLowerCase());
|
model.addAttribute("broadcaster", broadcaster.toLowerCase());
|
||||||
return "broadcast";
|
return "broadcast";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addVersionAttributes(Model model) {
|
||||||
|
model.addAttribute("version", versionService.getVersion());
|
||||||
|
model.addAttribute("releaseVersion", versionService.getReleaseVersion());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,21 +12,32 @@ import java.io.InputStreamReader;
|
|||||||
public class VersionService {
|
public class VersionService {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(VersionService.class);
|
private static final Logger LOG = LoggerFactory.getLogger(VersionService.class);
|
||||||
private final String version;
|
private final String version;
|
||||||
|
private final String releaseVersion;
|
||||||
|
|
||||||
public VersionService() {
|
public VersionService() {
|
||||||
this.version = resolveVersion();
|
this.version = resolveVersion();
|
||||||
|
this.releaseVersion = normalizeReleaseVersion(this.version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getVersion() {
|
public String getVersion() {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getReleaseVersion() {
|
||||||
|
return releaseVersion;
|
||||||
|
}
|
||||||
|
|
||||||
private String resolveVersion() {
|
private String resolveVersion() {
|
||||||
String manifestVersion = getClass().getPackage().getImplementationVersion();
|
String manifestVersion = getClass().getPackage().getImplementationVersion();
|
||||||
if (manifestVersion != null && !manifestVersion.isBlank()) {
|
if (manifestVersion != null && !manifestVersion.isBlank()) {
|
||||||
return manifestVersion;
|
return manifestVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String pomVersion = getPomVersion();
|
||||||
|
if (pomVersion != null && !pomVersion.isBlank()) {
|
||||||
|
return pomVersion;
|
||||||
|
}
|
||||||
|
|
||||||
String gitDescribeVersion = getGitVersionString();
|
String gitDescribeVersion = getGitVersionString();
|
||||||
if (gitDescribeVersion != null) {
|
if (gitDescribeVersion != null) {
|
||||||
return "git-" + gitDescribeVersion;
|
return "git-" + gitDescribeVersion;
|
||||||
@@ -35,6 +46,38 @@ public class VersionService {
|
|||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String normalizeReleaseVersion(String baseVersion) {
|
||||||
|
if (baseVersion == null || baseVersion.isBlank()) {
|
||||||
|
return "latest";
|
||||||
|
}
|
||||||
|
|
||||||
|
String normalized = baseVersion.trim();
|
||||||
|
normalized = normalized.replaceFirst("^git-", "");
|
||||||
|
normalized = normalized.replaceFirst("(?i)^v", "");
|
||||||
|
normalized = normalized.replaceFirst("-SNAPSHOT$", "");
|
||||||
|
if (normalized.isBlank()) {
|
||||||
|
return "latest";
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPomVersion() {
|
||||||
|
try (var inputStream = getClass().getResourceAsStream("/META-INF/maven/dev.kruhlmann/imgfloat/pom.properties")) {
|
||||||
|
if (inputStream == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var properties = new java.util.Properties();
|
||||||
|
properties.load(inputStream);
|
||||||
|
String pomVersion = properties.getProperty("version");
|
||||||
|
if (pomVersion != null && !pomVersion.isBlank()) {
|
||||||
|
return pomVersion.trim();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.warn("Unable to read version from pom.properties", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private String getGitVersionString() {
|
private String getGitVersionString() {
|
||||||
try {
|
try {
|
||||||
Process check = new ProcessBuilder("git", "--version")
|
Process check = new ProcessBuilder("git", "--version")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "imgfloat-electron",
|
"name": "imgfloat-electron",
|
||||||
"version": "1.0.0",
|
"version": "0.0.1",
|
||||||
"description": "Electron wrapper for the Imgfloat overlay",
|
"description": "Electron wrapper for the Imgfloat overlay",
|
||||||
"main": "app.js",
|
"main": "app.js",
|
||||||
"build": {
|
"build": {
|
||||||
|
|||||||
@@ -385,6 +385,67 @@ body {
|
|||||||
border-color: rgba(124, 58, 237, 0.18);
|
border-color: rgba(124, 58, 237, 0.18);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.download-section {
|
||||||
|
margin-top: 26px;
|
||||||
|
padding: 20px;
|
||||||
|
background: rgba(11, 18, 32, 0.92);
|
||||||
|
border-radius: 14px;
|
||||||
|
border: 1px solid #1f2937;
|
||||||
|
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.45);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-header h2, .download-header h3 {
|
||||||
|
margin: 6px 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-inline {
|
||||||
|
font-weight: 700;
|
||||||
|
color: #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-card {
|
||||||
|
border: 1px solid #1f2937;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 14px;
|
||||||
|
background: rgba(15, 23, 42, 0.82);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-card--active {
|
||||||
|
border-color: rgba(124, 58, 237, 0.55);
|
||||||
|
box-shadow: 0 16px 40px rgba(124, 58, 237, 0.22);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-card .button {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-card-block {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.eyebrow {
|
.eyebrow {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
|
|||||||
40
src/main/resources/static/js/downloads.js
Normal file
40
src/main/resources/static/js/downloads.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
function detectPlatform() {
|
||||||
|
const navigatorPlatform = (navigator.userAgentData?.platform || navigator.platform || '').toLowerCase();
|
||||||
|
const userAgent = (navigator.userAgent || '').toLowerCase();
|
||||||
|
const platformString = `${navigatorPlatform} ${userAgent}`;
|
||||||
|
|
||||||
|
if (platformString.includes('mac') || platformString.includes('darwin')) {
|
||||||
|
return 'mac';
|
||||||
|
}
|
||||||
|
if (platformString.includes('win')) {
|
||||||
|
return 'windows';
|
||||||
|
}
|
||||||
|
if (platformString.includes('linux')) {
|
||||||
|
return 'linux';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function markRecommendedDownload(section) {
|
||||||
|
const cards = Array.from(section.querySelectorAll('.download-card'));
|
||||||
|
if (!cards.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const platform = detectPlatform();
|
||||||
|
const preferredCard = cards.find((card) => card.dataset.platform === platform) || cards[0];
|
||||||
|
|
||||||
|
cards.forEach((card) => {
|
||||||
|
const isPreferred = card === preferredCard;
|
||||||
|
card.classList.toggle('download-card--active', isPreferred);
|
||||||
|
const badge = card.querySelector('.recommended-badge');
|
||||||
|
if (badge) {
|
||||||
|
badge.classList.toggle('hidden', !isPreferred);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const downloadSections = document.querySelectorAll('.download-section, .download-card-block');
|
||||||
|
downloadSections.forEach(markRecommendedDownload);
|
||||||
|
});
|
||||||
@@ -104,8 +104,45 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="card download-card-block">
|
||||||
|
<div class="download-header">
|
||||||
|
<div>
|
||||||
|
<p class="eyebrow">Desktop app</p>
|
||||||
|
<h3>Download Imgfloat</h3>
|
||||||
|
<p class="muted">Version <span class="version-inline" th:text="${releaseVersion}">0.0.1</span> · build <span class="version-inline" th:text="${version}">unknown</span></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="download-grid">
|
||||||
|
<div class="download-card" data-platform="mac">
|
||||||
|
<div class="download-card-header">
|
||||||
|
<p class="eyebrow">macOS</p>
|
||||||
|
<span class="badge soft recommended-badge hidden">Recommended</span>
|
||||||
|
</div>
|
||||||
|
<p class="muted">Apple Silicon build (ARM64)</p>
|
||||||
|
<a class="button block" th:href="'https://github.com/Kruhlmann/imgfloat-j/releases/download/' + ${releaseVersion} + '/Imgfloat-' + ${releaseVersion} + '-arm64.dmg'">Download .dmg</a>
|
||||||
|
</div>
|
||||||
|
<div class="download-card" data-platform="windows">
|
||||||
|
<div class="download-card-header">
|
||||||
|
<p class="eyebrow">Windows</p>
|
||||||
|
<span class="badge soft recommended-badge hidden">Recommended</span>
|
||||||
|
</div>
|
||||||
|
<p class="muted">Installer for Windows 10 and 11</p>
|
||||||
|
<a class="button block" th:href="'https://github.com/Kruhlmann/imgfloat-j/releases/download/' + ${releaseVersion} + '/Imgfloat.Setup.' + ${releaseVersion} + '.exe'">Download .exe</a>
|
||||||
|
</div>
|
||||||
|
<div class="download-card" data-platform="linux">
|
||||||
|
<div class="download-card-header">
|
||||||
|
<p class="eyebrow">Linux</p>
|
||||||
|
<span class="badge soft recommended-badge hidden">Recommended</span>
|
||||||
|
</div>
|
||||||
|
<p class="muted">AppImage for most distributions</p>
|
||||||
|
<a class="button block" th:href="'https://github.com/Kruhlmann/imgfloat-j/releases/download/' + ${releaseVersion} + '/Imgfloat-' + ${releaseVersion} + '.AppImage'">Download AppImage</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<script src="/js/toast.js"></script>
|
<script src="/js/toast.js"></script>
|
||||||
|
<script src="/js/downloads.js"></script>
|
||||||
<script th:inline="javascript">
|
<script th:inline="javascript">
|
||||||
const broadcaster = /*[[${channel}]]*/ '';
|
const broadcaster = /*[[${channel}]]*/ '';
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -29,6 +29,40 @@
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<section class="download-section">
|
||||||
|
<div class="download-header">
|
||||||
|
<p class="eyebrow">Desktop app</p>
|
||||||
|
<h2>Download Imgfloat</h2>
|
||||||
|
<p class="muted">Version <span class="version-inline" th:text="${releaseVersion}">0.0.1</span> for Windows, macOS, and Linux.</p>
|
||||||
|
</div>
|
||||||
|
<div class="download-grid">
|
||||||
|
<div class="download-card" data-platform="mac">
|
||||||
|
<div class="download-card-header">
|
||||||
|
<p class="eyebrow">macOS</p>
|
||||||
|
<span class="badge soft recommended-badge hidden">Recommended</span>
|
||||||
|
</div>
|
||||||
|
<p class="muted">Apple Silicon build (ARM64)</p>
|
||||||
|
<a class="button block" th:href="'https://github.com/Kruhlmann/imgfloat-j/releases/download/' + ${releaseVersion} + '/Imgfloat-' + ${releaseVersion} + '-arm64.dmg'">Download .dmg</a>
|
||||||
|
</div>
|
||||||
|
<div class="download-card" data-platform="windows">
|
||||||
|
<div class="download-card-header">
|
||||||
|
<p class="eyebrow">Windows</p>
|
||||||
|
<span class="badge soft recommended-badge hidden">Recommended</span>
|
||||||
|
</div>
|
||||||
|
<p class="muted">Installer for Windows 10 and 11</p>
|
||||||
|
<a class="button block" th:href="'https://github.com/Kruhlmann/imgfloat-j/releases/download/' + ${releaseVersion} + '/Imgfloat.Setup.' + ${releaseVersion} + '.exe'">Download .exe</a>
|
||||||
|
</div>
|
||||||
|
<div class="download-card" data-platform="linux">
|
||||||
|
<div class="download-card-header">
|
||||||
|
<p class="eyebrow">Linux</p>
|
||||||
|
<span class="badge soft recommended-badge hidden">Recommended</span>
|
||||||
|
</div>
|
||||||
|
<p class="muted">AppImage for most distributions</p>
|
||||||
|
<a class="button block" th:href="'https://github.com/Kruhlmann/imgfloat-j/releases/download/' + ${releaseVersion} + '/Imgfloat-' + ${releaseVersion} + '.AppImage'">Download AppImage</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<footer class="landing-meta">
|
<footer class="landing-meta">
|
||||||
<div class="build-chip">
|
<div class="build-chip">
|
||||||
<span class="muted">Build</span>
|
<span class="muted">Build</span>
|
||||||
@@ -36,5 +70,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
<script src="/js/downloads.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user