mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-12-11 09:27:30 +00:00
feat: add older and nightly downloads page
This commit is contained in:
parent
36cf0a8141
commit
484068fc38
42
website/package-lock.json
generated
42
website/package-lock.json
generated
@ -10,12 +10,15 @@
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "1.6.1",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.5.1",
|
||||
"@octokit/openapi-types": "^19.1.0",
|
||||
"@octokit/rest": "^20.0.2",
|
||||
"date-fns": "^3.3.1",
|
||||
"highlight.js": "11.9.0",
|
||||
"lucide-svelte": "^0.323.0",
|
||||
"remark-container": "^0.1.2",
|
||||
"remark-github": "^12.0.0",
|
||||
"svelte-fa": "^4.0.2"
|
||||
"svelte-fa": "^4.0.2",
|
||||
"svelte-markdown": "^0.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.28.1",
|
||||
@ -1231,6 +1234,11 @@
|
||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/marked": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/marked/-/marked-5.0.2.tgz",
|
||||
"integrity": "sha512-OucS4KMHhFzhz27KxmWg7J+kIYqyqoW5kdIEI319hqARQQUTqhao3M/F+uFnDXD0Rg72iDDZxZNxq5gvctmLlg=="
|
||||
},
|
||||
"node_modules/@types/mdast": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz",
|
||||
@ -1878,6 +1886,15 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.3.1.tgz",
|
||||
"integrity": "sha512-y8e109LYGgoQDveiEBD3DYXKba1jWf5BA8YU1FL5Tvm0BTdEfy54WLCwnuYWZNnzzvALy/QQ4Hov+Q9RVRv+Zw==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/kossnocorp"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
@ -2946,6 +2963,17 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/marked": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-5.1.2.tgz",
|
||||
"integrity": "sha512-ahRPGXJpjMjwSOlBoTMZAK7ATXkli5qCPxZ21TG44rx1KEo44bii4ekgTDQPNRQ4Kh7JMb9Ub1PVk1NxRSsorg==",
|
||||
"bin": {
|
||||
"marked": "bin/marked.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-find-and-replace": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz",
|
||||
@ -4270,6 +4298,18 @@
|
||||
"svelte": "^3.19.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-markdown": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/svelte-markdown/-/svelte-markdown-0.4.1.tgz",
|
||||
"integrity": "sha512-pOlLY6EruKJaWI9my/2bKX8PdTeP5CM0s4VMmwmC2prlOkjAf+AOmTM4wW/l19Y6WZ87YmP8+ZCJCCwBChWjYw==",
|
||||
"dependencies": {
|
||||
"@types/marked": "^5.0.1",
|
||||
"marked": "^5.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-preprocess": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.3.tgz",
|
||||
|
||||
@ -44,11 +44,14 @@
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "1.6.1",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.5.1",
|
||||
"@octokit/openapi-types": "^19.1.0",
|
||||
"@octokit/rest": "^20.0.2",
|
||||
"date-fns": "^3.3.1",
|
||||
"highlight.js": "11.9.0",
|
||||
"lucide-svelte": "^0.323.0",
|
||||
"remark-container": "^0.1.2",
|
||||
"remark-github": "^12.0.0",
|
||||
"svelte-fa": "^4.0.2"
|
||||
"svelte-fa": "^4.0.2",
|
||||
"svelte-markdown": "^0.4.1"
|
||||
}
|
||||
}
|
||||
|
||||
25
website/src/components/downloads/download-items.svelte
Normal file
25
website/src/components/downloads/download-items.svelte
Normal file
@ -0,0 +1,25 @@
|
||||
<script lang="ts">
|
||||
import type { IconDefinition } from '@fortawesome/free-brands-svg-icons';
|
||||
import Fa from 'svelte-fa';
|
||||
|
||||
export let links: Record<string, [string, IconDefinition[], string]>;
|
||||
</script>
|
||||
|
||||
<div class="grid sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
||||
{#each Object.entries(links) as link}
|
||||
<a
|
||||
href={link[1][0]}
|
||||
class="flex flex-col btn variant-ghost-primary rounded-xl p-0 overflow-hidden"
|
||||
>
|
||||
<div class="relative bg-primary-500 p-4 flex gap-4 justify-center rounded-t-xl w-full">
|
||||
{#each link[1][1] as icon}
|
||||
<Fa {icon} />
|
||||
{/each}
|
||||
<p class="chip variant-ghost-warning text-warning-400 absolute right-2 uppercase">
|
||||
{link[1][2]}
|
||||
</p>
|
||||
</div>
|
||||
<p class="p-4">{link[0]}</p>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
3
website/src/components/markdown/layout.svelte
Normal file
3
website/src/components/markdown/layout.svelte
Normal file
@ -0,0 +1,3 @@
|
||||
<article class="prose lg:prose-lg max-w-3xl">
|
||||
<slot />
|
||||
</article>
|
||||
@ -20,7 +20,9 @@
|
||||
>
|
||||
<Menu />
|
||||
</button>
|
||||
<h2 class="text-3xl">Spotube</h2>
|
||||
<h2 class="text-3xl">
|
||||
<a href="/"> Spotube </a>
|
||||
</h2>
|
||||
</div>
|
||||
<a
|
||||
class="mw-2 md:me-4"
|
||||
|
||||
@ -44,3 +44,18 @@ export const extendedDownloadLinks: Record<string, [string, IconDefinition[], st
|
||||
],
|
||||
iPhone: [`${releasesUrl}/Spotube-iOS.ipa`, [faApple], 'ipa']
|
||||
};
|
||||
|
||||
const nightlyReleaseUrl = 'https://github.com/KRTirtho/Spotube/releases/download/nightly';
|
||||
|
||||
export const extendedNightlyDownloadLinks: Record<string, [string, IconDefinition[], string]> = {
|
||||
Android: [`${nightlyReleaseUrl}/Spotube-android-all-arch.apk`, [faAndroid], 'apk'],
|
||||
Windows: [`${nightlyReleaseUrl}/Spotube-windows-x86_64-setup.exe`, [faWindows], 'exe'],
|
||||
macOS: [`${nightlyReleaseUrl}/Spotube-macos-universal.dmg`, [faApple], 'dmg'],
|
||||
'Ubuntu, Debian': [`${nightlyReleaseUrl}/Spotube-linux-x86_64.deb`, [faUbuntu, faDebian], 'deb'],
|
||||
'Fedora, Redhat, Opensuse': [
|
||||
`${nightlyReleaseUrl}/Spotube-linux-x86_64.rpm`,
|
||||
[faFedora, faRedhat, faOpensuse],
|
||||
'rpm'
|
||||
],
|
||||
iPhone: [`${nightlyReleaseUrl}/Spotube-iOS.ipa`, [faApple], 'ipa']
|
||||
};
|
||||
|
||||
@ -1,7 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { extendedDownloadLinks } from '$lib';
|
||||
import { Download } from 'lucide-svelte';
|
||||
import Fa from 'svelte-fa';
|
||||
import { History, Sparkles, Package } from 'lucide-svelte';
|
||||
import DownloadItems from '../../components/downloads/download-items.svelte';
|
||||
|
||||
const otherDownloads: [string, string, any][] = [
|
||||
['/downloads/packages', 'CLI Packages Managers', Package],
|
||||
['/downloads/older', 'Older Versions', History],
|
||||
['/downloads/nightly', 'Nightly Builds', Sparkles]
|
||||
];
|
||||
</script>
|
||||
|
||||
<section class="p-4 md:p-16">
|
||||
@ -13,18 +20,19 @@
|
||||
<h5 class="h5">Spotube is available for every platform</h5>
|
||||
<br />
|
||||
|
||||
<div class="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
||||
{#each Object.entries(extendedDownloadLinks) as links}
|
||||
<a href={links[1][0]} class="flex flex-col btn variant-ghost-primary rounded-xl p-0">
|
||||
<div class="relative bg-primary-500 p-4 flex gap-4 justify-center rounded-t-xl w-full">
|
||||
{#each links[1][1] as icon}
|
||||
<Fa {icon} />
|
||||
{/each}
|
||||
<p class="chip variant-ghost-error text-error-400 absolute right-2 uppercase">
|
||||
{links[1][2]}
|
||||
</p>
|
||||
<DownloadItems links={extendedDownloadLinks} />
|
||||
|
||||
<br /><br /><br />
|
||||
|
||||
<h2 class="h2">Other Downloads</h2>
|
||||
<br /><br />
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-2 max-w-3xl">
|
||||
{#each otherDownloads as download}
|
||||
<a href={download[0]}>
|
||||
<div class="btn rounded variant-soft-secondary flex flex-col items-center p-4 gap-4">
|
||||
<svelte:component this={download[2]} />
|
||||
<h5 class="h5">{download[1]}</h5>
|
||||
</div>
|
||||
<p class="p-4">{links[0]}</p>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
33
website/src/routes/downloads/nightly/+page.svelte
Normal file
33
website/src/routes/downloads/nightly/+page.svelte
Normal file
@ -0,0 +1,33 @@
|
||||
<script>
|
||||
import { AlertTriangle, Bug, Sparkles } from 'lucide-svelte';
|
||||
import DownloadItems from '../../../components/downloads/download-items.svelte';
|
||||
import { extendedNightlyDownloadLinks } from '$lib';
|
||||
</script>
|
||||
|
||||
<section class="p-4 md:p-16">
|
||||
<h2 class="h2 flex items-center gap-4">
|
||||
Nightly Downloads
|
||||
<Sparkles class="inline" size={30} />
|
||||
</h2>
|
||||
<br /><br />
|
||||
<aside class="alert variant-ghost-warning">
|
||||
<div><AlertTriangle class="text-warning-500" /></div>
|
||||
<div class="alert-message">
|
||||
<h3 class="h3">Nightly versions may contain bugs <Bug class="inline" /></h3>
|
||||
<p>
|
||||
Although Nightly versions are packed with newest and greatest features, it's often unstable
|
||||
and not tested by the maintainers and publisher(s).
|
||||
<br />
|
||||
<span class="text-error-500 underline decoration-dotted">
|
||||
So use it at your own risk.
|
||||
</span>
|
||||
<span>
|
||||
Go to <a href="/downloads" class="anchor">Downloads</a> for more stable releases.
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<br />
|
||||
|
||||
<DownloadItems links={extendedNightlyDownloadLinks} />
|
||||
</section>
|
||||
138
website/src/routes/downloads/older/+page.svelte
Normal file
138
website/src/routes/downloads/older/+page.svelte
Normal file
@ -0,0 +1,138 @@
|
||||
<script lang="ts">
|
||||
import SvelteMarkdown from 'svelte-markdown';
|
||||
import type { PageData } from './$types';
|
||||
import { formatDistanceToNow, formatRelative } from 'date-fns';
|
||||
import Layout from '../../../components/markdown/layout.svelte';
|
||||
import { Accordion, AccordionItem } from '@skeletonlabs/skeleton';
|
||||
import { Book, History } from 'lucide-svelte';
|
||||
import {
|
||||
faAndroid,
|
||||
faApple,
|
||||
faGit,
|
||||
faGooglePlay,
|
||||
faLinux,
|
||||
faWindows,
|
||||
type IconDefinition
|
||||
} from '@fortawesome/free-brands-svg-icons';
|
||||
import Fa from 'svelte-fa';
|
||||
import type { RestEndpointMethodTypes } from '@octokit/rest';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
function getIcon(assetUrl: string) {
|
||||
assetUrl = assetUrl.toLowerCase();
|
||||
if (assetUrl.includes('linux')) return faLinux;
|
||||
if (assetUrl.includes('windows')) return faWindows;
|
||||
if (assetUrl.includes('mac')) return faApple;
|
||||
if (assetUrl.includes('android')) return faAndroid;
|
||||
if (assetUrl.includes('playstore')) return faGooglePlay;
|
||||
if (assetUrl.includes('ios')) return faApple;
|
||||
|
||||
return faGit;
|
||||
}
|
||||
|
||||
function formatName(assetName: string) {
|
||||
// format the assetName to be
|
||||
// {OS} ({package extension})
|
||||
|
||||
const lowerCasedAssetName = assetName.toLowerCase();
|
||||
const extension = assetName.split('.').at(-1);
|
||||
|
||||
if (lowerCasedAssetName.includes('linux')) return [`Linux`, extension];
|
||||
if (lowerCasedAssetName.includes('windows')) return [`Windows`, extension];
|
||||
if (lowerCasedAssetName.includes('mac')) return [`macOS`, extension];
|
||||
if (lowerCasedAssetName.includes('android') || lowerCasedAssetName.includes('playstore'))
|
||||
return [`Android`, extension];
|
||||
if (lowerCasedAssetName.includes('ios')) return [`iOS`, extension];
|
||||
|
||||
return [assetName.replace(`.${extension}`, ''), extension];
|
||||
}
|
||||
|
||||
type OctokitAsset =
|
||||
RestEndpointMethodTypes['repos']['listReleases']['response']['data'][0]['assets'][0];
|
||||
|
||||
function groupByOS(downloads: OctokitAsset[]) {
|
||||
return downloads.reduce(
|
||||
(acc, val) => {
|
||||
const lowName = val.name.toLowerCase();
|
||||
|
||||
if (lowName.includes('android') || lowName.includes('playstore'))
|
||||
acc['android'] = [...(acc.android ?? []), val];
|
||||
if (lowName.includes('linux')) acc['linux'] = [...(acc['linux'] ?? []), val];
|
||||
if (lowName.includes('windows')) acc['windows'] = [...(acc['windows'] ?? []), val];
|
||||
if (lowName.includes('ios')) acc['ios'] = [...(acc['ios'] ?? []), val];
|
||||
if (lowName.includes('mac')) acc['mac'] = [...(acc['mac'] ?? []), val];
|
||||
|
||||
return acc;
|
||||
},
|
||||
{} as Record<'android' | 'ios' | 'mac' | 'linux' | 'windows', OctokitAsset[]>
|
||||
);
|
||||
}
|
||||
|
||||
const icons: Record<string, [IconDefinition, string]> = {
|
||||
android: [faAndroid, '#3DDC84'],
|
||||
mac: [faApple, ''],
|
||||
ios: [faApple, ''],
|
||||
linux: [faLinux, '#000000'],
|
||||
windows: [faWindows, '#0078D7']
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="p-4 md:p-24">
|
||||
<div class="flex gap-2 items-center">
|
||||
<h2 class="h2">Older versions</h2>
|
||||
<History />
|
||||
</div>
|
||||
<br /><br />
|
||||
<Accordion>
|
||||
<div class="flex flex-col gap-5">
|
||||
{#each data.releases as release}
|
||||
<h4 class="h4" title={formatRelative(release.published_at ?? new Date(), new Date())}>
|
||||
{release.tag_name}
|
||||
<span class="text-sm font-normal">
|
||||
({formatDistanceToNow(release.published_at ?? new Date(), { addSuffix: true })})
|
||||
</span>
|
||||
</h4>
|
||||
<div class="flex flex-col gap-5">
|
||||
{#each Object.entries(groupByOS(release.assets)) as [osName, assets]}
|
||||
<div class="flex flex-col gap-4">
|
||||
<h5 class="h5 capitalize">
|
||||
<Fa class="inline" icon={icons[osName][0]} color={icons[osName][1]} />
|
||||
{osName}
|
||||
</h5>
|
||||
<div class="flex flex-wrap gap-4">
|
||||
{#each assets as asset}
|
||||
<a href={release.assets_url}>
|
||||
<button class="btn variant-glass-primary rounded p-0 flex flex-col gap-2">
|
||||
<span class="bg-primary-500 rounded-t p-3 w-full">
|
||||
<Fa class="inline" icon={getIcon(asset.browser_download_url)} />
|
||||
</span>
|
||||
<span class="p-4">
|
||||
{formatName(asset.name)[0]}
|
||||
<span class="chip variant-ghost-error">
|
||||
{formatName(asset.name)[1]}
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<AccordionItem>
|
||||
<svelte:fragment slot="lead">
|
||||
<Book />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="summary">Release Notes & Changelogs</svelte:fragment>
|
||||
<svelte:fragment slot="content">
|
||||
<Layout>
|
||||
<SvelteMarkdown source={release.body} />
|
||||
</Layout>
|
||||
</svelte:fragment>
|
||||
</AccordionItem>
|
||||
<hr />
|
||||
{/each}
|
||||
</div>
|
||||
</Accordion>
|
||||
</div>
|
||||
14
website/src/routes/downloads/older/+page.ts
Normal file
14
website/src/routes/downloads/older/+page.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import type { PageLoad } from './$types';
|
||||
import { Octokit } from '@octokit/rest';
|
||||
|
||||
const github = new Octokit();
|
||||
export const load: PageLoad = async () => {
|
||||
const { data: releases } = await github.repos.listReleases({
|
||||
owner: 'KRTirtho',
|
||||
repo: 'spotube'
|
||||
});
|
||||
|
||||
return {
|
||||
releases
|
||||
};
|
||||
};
|
||||
70
website/src/routes/downloads/packages/+page.svx
Normal file
70
website/src/routes/downloads/packages/+page.svx
Normal file
@ -0,0 +1,70 @@
|
||||
<script context="module">
|
||||
export let metadata = {
|
||||
title: 'CLI Packages Managers',
|
||||
author: 'Kingkor Roy Tirtho'
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { faLinux, faWindows } from '@fortawesome/free-brands-svg-icons';
|
||||
import Fa from 'svelte-fa';
|
||||
</script>
|
||||
|
||||
<div class="p-4 md:ps-24">
|
||||
<h2 class="h2">Package Managers</h2>
|
||||
|
||||
Spotube is available in various Package Managers supported by Platform
|
||||
|
||||
## <Fa class="inline" icon={faLinux} /> Linux
|
||||
### Flatpak
|
||||
|
||||
Make sure [Flatpak](https://flatpak.org) is installed in your Linux device & Run the following command in the terminal:
|
||||
|
||||
```bash
|
||||
$ flatpak install com.github.KRTirtho.Spotube
|
||||
````
|
||||
|
||||
### Arch User Repository (AUR)
|
||||
|
||||
If you're an Arch Linux user, you can also install Spotube from AUR.
|
||||
Make sure you have `yay`/`pamac`/`paru` installed in your system. And Run the Following command in the Terminal:
|
||||
|
||||
```bash
|
||||
$ yay -Sy spotube-bin
|
||||
```
|
||||
|
||||
```bash
|
||||
$ pamac install spotube-bin
|
||||
```
|
||||
|
||||
```bash
|
||||
$ paru -Sy spotube-bin
|
||||
```
|
||||
|
||||
## <Fa class="inline" icon={faWindows} color="#00A2F0" /> Windows
|
||||
|
||||
### Chocolatey
|
||||
|
||||
Spotube is available in [community.chocolatey.org](https://community.chocolatey.org) repo. If you have chocolatey install in your system just run following command in an Elevated Command Prompt or PowerShell:
|
||||
|
||||
```powershell
|
||||
$ choco install spotube
|
||||
```
|
||||
|
||||
### WinGet
|
||||
|
||||
Spotube is also available in the Official Windows PackageManager WinGet. Make sure you have WinGet installed in your Windows machine and run following in a Terminal:
|
||||
|
||||
```powershell
|
||||
$ winget install --id KRTirtho.Spotube
|
||||
```
|
||||
|
||||
### Scoop
|
||||
|
||||
Spotube is also available in [Scoop](https://scoop.sh) bucket. Make sure you have Scoop installed in your Windows machine and run following in a Terminal:
|
||||
|
||||
```powershell
|
||||
$ scoop bucket add extras
|
||||
$ scoop install spotube
|
||||
```
|
||||
</div>
|
||||
@ -1,20 +1,18 @@
|
||||
import adapter from '@sveltejs/adapter-static';
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
import { mdsvex } from 'mdsvex';
|
||||
import containers from 'remark-container';
|
||||
import github from 'remark-github';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
extensions: ['.svelte'],
|
||||
extensions: ['.svelte', '.svx', '.md'],
|
||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||
// for more information about preprocessors
|
||||
preprocess: [
|
||||
vitePreprocess(),
|
||||
mdsvex({
|
||||
extensions: ['.svx'],
|
||||
extensions: ['.svx', '.md'],
|
||||
highlight: {},
|
||||
remarkPlugins: [containers, github]
|
||||
layout: './src/components/markdown/layout.svelte'
|
||||
})
|
||||
],
|
||||
vitePlugin: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user