downgrade: chose the path of ads

This commit is contained in:
Kingkor Roy Tirtho 2024-12-13 00:17:19 +06:00
parent b32ec667a9
commit 12f3ec1776
18 changed files with 356 additions and 83 deletions

View File

@ -50,6 +50,7 @@
"highlight.js": "11.9.0", "highlight.js": "11.9.0",
"lucide-svelte": "^0.323.0", "lucide-svelte": "^0.323.0",
"mdsvex-relative-images": "^1.0.3", "mdsvex-relative-images": "^1.0.3",
"rehype-auto-ads": "^1.2.0",
"rehype-autolink-headings": "^7.1.0", "rehype-autolink-headings": "^7.1.0",
"rehype-slug": "^6.0.0", "rehype-slug": "^6.0.0",
"remark-container": "^0.1.2", "remark-container": "^0.1.2",

View File

@ -32,6 +32,9 @@ importers:
mdsvex-relative-images: mdsvex-relative-images:
specifier: ^1.0.3 specifier: ^1.0.3
version: 1.0.3 version: 1.0.3
rehype-auto-ads:
specifier: ^1.2.0
version: 1.2.0
rehype-autolink-headings: rehype-autolink-headings:
specifier: ^7.1.0 specifier: ^7.1.0
version: 7.1.0 version: 7.1.0
@ -783,6 +786,9 @@ packages:
color-name@1.1.4: color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
comma-separated-tokens@2.0.3:
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
commander@10.0.1: commander@10.0.1:
resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
engines: {node: '>=14'} engines: {node: '>=14'}
@ -873,6 +879,10 @@ packages:
emoji-regex@9.2.2: emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
entities@4.5.0:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
es6-promise@3.3.1: es6-promise@3.3.1:
resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
@ -1069,15 +1079,27 @@ packages:
resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
hast-util-from-html@2.0.3:
resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==}
hast-util-from-parse5@8.0.2:
resolution: {integrity: sha512-SfMzfdAi/zAoZ1KkFEyyeXBn7u/ShQrfd675ZEE9M3qj+PMFX05xubzRyF76CCSJu8au9jgVxDV1+okFvgZU4A==}
hast-util-heading-rank@3.0.0: hast-util-heading-rank@3.0.0:
resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==} resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==}
hast-util-is-element@3.0.0: hast-util-is-element@3.0.0:
resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==}
hast-util-parse-selector@4.0.0:
resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==}
hast-util-to-string@3.0.0: hast-util-to-string@3.0.0:
resolution: {integrity: sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==} resolution: {integrity: sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==}
hastscript@9.0.0:
resolution: {integrity: sha512-jzaLBGavEDKHrc5EfFImKN7nZKKBdSLIdGvCwDZ9TfzbF2ffXiov8CKE445L2Z1Ek2t/m4SKQ2j6Ipv7NyUolw==}
highlight.js@11.9.0: highlight.js@11.9.0:
resolution: {integrity: sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==} resolution: {integrity: sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==}
engines: {node: '>=12.0.0'} engines: {node: '>=12.0.0'}
@ -1467,6 +1489,9 @@ packages:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'} engines: {node: '>=6'}
parse5@7.2.1:
resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==}
path-exists@4.0.0: path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -1609,6 +1634,9 @@ packages:
resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}
engines: {node: '>=6'} engines: {node: '>=6'}
property-information@6.5.0:
resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
punycode@2.3.1: punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -1634,6 +1662,9 @@ packages:
resolution: {integrity: sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==} resolution: {integrity: sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==}
engines: {node: '>=8'} engines: {node: '>=8'}
rehype-auto-ads@1.2.0:
resolution: {integrity: sha512-w0ysjJQginhKai13wcUF/4t1fu3UvPsVt4Y3htGGGs6ojA+J5Nz01I1NOqwrOhgSoT5Bfv7Mihww6tmtV108+g==}
rehype-autolink-headings@7.1.0: rehype-autolink-headings@7.1.0:
resolution: {integrity: sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==} resolution: {integrity: sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==}
@ -1960,6 +1991,9 @@ packages:
util-deprecate@1.0.2: util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
vfile-location@5.0.3:
resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==}
vfile-message@2.0.4: vfile-message@2.0.4:
resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==} resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==}
@ -2016,6 +2050,9 @@ packages:
vite: vite:
optional: true optional: true
web-namespaces@2.0.1:
resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
which@2.0.2: which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@ -2660,6 +2697,8 @@ snapshots:
color-name@1.1.4: {} color-name@1.1.4: {}
comma-separated-tokens@2.0.3: {}
commander@10.0.1: {} commander@10.0.1: {}
commander@4.1.1: {} commander@4.1.1: {}
@ -2725,6 +2764,8 @@ snapshots:
emoji-regex@9.2.2: {} emoji-regex@9.2.2: {}
entities@4.5.0: {}
es6-promise@3.3.1: {} es6-promise@3.3.1: {}
esbuild@0.19.12: esbuild@0.19.12:
@ -2982,6 +3023,26 @@ snapshots:
dependencies: dependencies:
function-bind: 1.1.2 function-bind: 1.1.2
hast-util-from-html@2.0.3:
dependencies:
'@types/hast': 3.0.4
devlop: 1.1.0
hast-util-from-parse5: 8.0.2
parse5: 7.2.1
vfile: 6.0.1
vfile-message: 4.0.2
hast-util-from-parse5@8.0.2:
dependencies:
'@types/hast': 3.0.4
'@types/unist': 3.0.2
devlop: 1.1.0
hastscript: 9.0.0
property-information: 6.5.0
vfile: 6.0.1
vfile-location: 5.0.3
web-namespaces: 2.0.1
hast-util-heading-rank@3.0.0: hast-util-heading-rank@3.0.0:
dependencies: dependencies:
'@types/hast': 3.0.4 '@types/hast': 3.0.4
@ -2990,10 +3051,22 @@ snapshots:
dependencies: dependencies:
'@types/hast': 3.0.4 '@types/hast': 3.0.4
hast-util-parse-selector@4.0.0:
dependencies:
'@types/hast': 3.0.4
hast-util-to-string@3.0.0: hast-util-to-string@3.0.0:
dependencies: dependencies:
'@types/hast': 3.0.4 '@types/hast': 3.0.4
hastscript@9.0.0:
dependencies:
'@types/hast': 3.0.4
comma-separated-tokens: 2.0.3
hast-util-parse-selector: 4.0.0
property-information: 6.5.0
space-separated-tokens: 2.0.2
highlight.js@11.9.0: {} highlight.js@11.9.0: {}
ignore@5.3.1: {} ignore@5.3.1: {}
@ -3510,6 +3583,10 @@ snapshots:
dependencies: dependencies:
callsites: 3.1.0 callsites: 3.1.0
parse5@7.2.1:
dependencies:
entities: 4.5.0
path-exists@4.0.0: {} path-exists@4.0.0: {}
path-is-absolute@1.0.1: {} path-is-absolute@1.0.1: {}
@ -3617,6 +3694,8 @@ snapshots:
prismjs@1.29.0: {} prismjs@1.29.0: {}
property-information@6.5.0: {}
punycode@2.3.1: {} punycode@2.3.1: {}
purgecss@6.0.0-alpha.0: purgecss@6.0.0-alpha.0:
@ -3640,6 +3719,15 @@ snapshots:
regexparam@3.0.0: {} regexparam@3.0.0: {}
rehype-auto-ads@1.2.0:
dependencies:
'@types/hast': 3.0.4
hast-util-from-html: 2.0.3
hast-util-is-element: 3.0.0
unified: 11.0.4
unist-util-visit-parents: 6.0.1
vfile: 6.0.1
rehype-autolink-headings@7.1.0: rehype-autolink-headings@7.1.0:
dependencies: dependencies:
'@types/hast': 3.0.4 '@types/hast': 3.0.4
@ -4072,6 +4160,11 @@ snapshots:
util-deprecate@1.0.2: {} util-deprecate@1.0.2: {}
vfile-location@5.0.3:
dependencies:
'@types/unist': 3.0.2
vfile: 6.0.1
vfile-message@2.0.4: vfile-message@2.0.4:
dependencies: dependencies:
'@types/unist': 2.0.10 '@types/unist': 2.0.10
@ -4119,6 +4212,8 @@ snapshots:
optionalDependencies: optionalDependencies:
vite: 5.1.0(@types/node@20.11.16) vite: 5.1.0(@types/node@20.11.16)
web-namespaces@2.0.1: {}
which@2.0.2: which@2.0.2:
dependencies: dependencies:
isexe: 2.0.0 isexe: 2.0.0

View File

@ -3,6 +3,7 @@ title: Spotube Basics
author: Kingkor Roy Tirtho author: Kingkor Roy Tirtho
date: 2024-02-10 date: 2024-02-10
published: true published: true
cover_img: /images/spotube-basics/cover.jpg
--- ---
Spotube is an open-source Spotify client that allows users to stream music from Spotify. To use Spotube, you need to sign in with your Spotify account. Here's a step-by-step guide on how to sign in to Spotube. Spotube is an open-source Spotify client that allows users to stream music from Spotify. To use Spotube, you need to sign in with your Spotify account. Here's a step-by-step guide on how to sign in to Spotube.

View File

@ -17,6 +17,10 @@ declare namespace App {
} }
} }
declare module '@fortawesome/pro-solid-svg-icons/index.es' { declare namespace globalThis {
export * from '@fortawesome/pro-solid-svg-icons'; declare var adsbygoogle: any[];
}
declare module "@fortawesome/pro-solid-svg-icons/index.es" {
export * from "@fortawesome/pro-solid-svg-icons";
} }

View File

@ -13,6 +13,9 @@
<link rel="apple-touch-icon" href="%sveltekit.assets%/apple-touch-icon.png" /> <link rel="apple-touch-icon" href="%sveltekit.assets%/apple-touch-icon.png" />
<!-- Android Chrome --> <!-- Android Chrome -->
<link rel="manifest" href="%sveltekit.assets%/manifest.json" /> <link rel="manifest" href="%sveltekit.assets%/manifest.json" />
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-6419300932495863"
crossorigin="anonymous"></script>
%sveltekit.head% %sveltekit.head%
</head> </head>

View File

@ -0,0 +1,32 @@
<script lang="ts">
import { onMount } from 'svelte';
export let adSlot: number;
export let adFormat: 'auto' | 'fluid';
// biome-ignore lint/style/useConst: This is just props
export let fullWidthResponsive = true;
// biome-ignore lint/style/useConst: This is just props
export let style = 'display:block';
// biome-ignore lint/style/useConst: This is just props
export let adLayout: 'in-article' | 'in-feed' | 'in-page' | undefined = undefined;
// biome-ignore lint/style/useConst: This is just props
export let adLayoutKey: string | undefined = undefined;
const AD_CLIENT = 'ca-pub-6419300932495863';
onMount(() => {
// biome-ignore lint/suspicious/noAssignInExpressions: <explanation>
(window.adsbygoogle = window.adsbygoogle || []).push({});
});
</script>
<ins
class="adsbygoogle"
{style}
data-ad-layout={adLayout}
data-ad-client={AD_CLIENT}
data-ad-slot={adSlot}
data-ad-format={adFormat}
data-full-width-responsive={fullWidthResponsive}
data-ad-layout-key={adLayoutKey}
></ins>

View File

@ -17,10 +17,8 @@
</script> </script>
<div class="inline-flex gap-2"> <div class="inline-flex gap-2">
{#if label}
<label class="ps-4">{label}</label>
{/if}
<SlideToggle <SlideToggle
label={label}
active="bg-primary-backdrop-token" active="bg-primary-backdrop-token"
size="sm" size="sm"
name="dark-mode" name="dark-mode"

View File

@ -6,56 +6,99 @@ import {
faOpensuse, faOpensuse,
faUbuntu, faUbuntu,
faWindows, faWindows,
faRedhat faRedhat,
} from '@fortawesome/free-brands-svg-icons'; } from "@fortawesome/free-brands-svg-icons";
import { type IconDefinition } from '@fortawesome/free-brands-svg-icons/index'; import type { IconDefinition } from "@fortawesome/free-brands-svg-icons/index";
import { Home, Newspaper, Download } from 'lucide-svelte'; import { Home, Newspaper, Download } from "lucide-svelte";
export const routes: Record<string, [string, any]> = { export const routes: Record<string, [string, any]> = {
'/': ['Home', Home], "/": ["Home", Home],
'/blog': ['Blog', Newspaper], "/blog": ["Blog", Newspaper],
'/downloads': ['Downloads', Download], "/downloads": ["Downloads", Download],
'/about': ['About', null] "/about": ["About", null],
}; };
const releasesUrl = 'https://github.com/KRTirtho/Spotube/releases/latest/download'; const releasesUrl =
"https://github.com/KRTirtho/Spotube/releases/latest/download";
export const downloadLinks: Record<string, [string, IconDefinition[]]> = { export const downloadLinks: Record<string, [string, IconDefinition[]]> = {
'Android Apk': [`${releasesUrl}/Spotube-android-all-arch.apk`, [faAndroid]], "Android Apk": [`${releasesUrl}/Spotube-android-all-arch.apk`, [faAndroid]],
'Windows Executable': [`${releasesUrl}/Spotube-windows-x86_64-setup.exe`, [faWindows]], "Windows Executable": [
'macOS Dmg': [`${releasesUrl}/Spotube-macos-universal.dmg`, [faApple]], `${releasesUrl}/Spotube-windows-x86_64-setup.exe`,
'Ubuntu, Debian': [`${releasesUrl}/Spotube-linux-x86_64.deb`, [faUbuntu, faDebian]], [faWindows],
'Fedora, Redhat, Opensuse': [
`${releasesUrl}/Spotube-linux-x86_64.rpm`,
[faFedora, faRedhat, faOpensuse]
], ],
'iPhone Ipa': [`${releasesUrl}/Spotube-iOS.ipa`, [faApple]] "macOS Dmg": [`${releasesUrl}/Spotube-macos-universal.dmg`, [faApple]],
}; "Ubuntu, Debian": [
`${releasesUrl}/Spotube-linux-x86_64.deb`,
export const extendedDownloadLinks: Record<string, [string, IconDefinition[], string]> = { [faUbuntu, faDebian],
Android: [`${releasesUrl}/Spotube-android-all-arch.apk`, [faAndroid], 'apk'], ],
Windows: [`${releasesUrl}/Spotube-windows-x86_64-setup.exe`, [faWindows], 'exe'], "Fedora, Redhat, Opensuse": [
macOS: [`${releasesUrl}/Spotube-macos-universal.dmg`, [faApple], 'dmg'],
'Ubuntu, Debian': [`${releasesUrl}/Spotube-linux-x86_64.deb`, [faUbuntu, faDebian], 'deb'],
'Fedora, Redhat, Opensuse': [
`${releasesUrl}/Spotube-linux-x86_64.rpm`, `${releasesUrl}/Spotube-linux-x86_64.rpm`,
[faFedora, faRedhat, faOpensuse], [faFedora, faRedhat, faOpensuse],
'rpm'
], ],
iPhone: [`${releasesUrl}/Spotube-iOS.ipa`, [faApple], 'ipa'] "iPhone Ipa": [`${releasesUrl}/Spotube-iOS.ipa`, [faApple]],
}; };
const nightlyReleaseUrl = 'https://github.com/KRTirtho/Spotube/releases/download/nightly'; export const extendedDownloadLinks: Record<
string,
[string, IconDefinition[], string]
> = {
Android: [`${releasesUrl}/Spotube-android-all-arch.apk`, [faAndroid], "apk"],
Windows: [
`${releasesUrl}/Spotube-windows-x86_64-setup.exe`,
[faWindows],
"exe",
],
macOS: [`${releasesUrl}/Spotube-macos-universal.dmg`, [faApple], "dmg"],
"Ubuntu, Debian": [
`${releasesUrl}/Spotube-linux-x86_64.deb`,
[faUbuntu, faDebian],
"deb",
],
"Fedora, Redhat, Opensuse": [
`${releasesUrl}/Spotube-linux-x86_64.rpm`,
[faFedora, faRedhat, faOpensuse],
"rpm",
],
iPhone: [`${releasesUrl}/Spotube-iOS.ipa`, [faApple], "ipa"],
};
export const extendedNightlyDownloadLinks: Record<string, [string, IconDefinition[], string]> = { const nightlyReleaseUrl =
Android: [`${nightlyReleaseUrl}/Spotube-android-all-arch.apk`, [faAndroid], 'apk'], "https://github.com/KRTirtho/Spotube/releases/download/nightly";
Windows: [`${nightlyReleaseUrl}/Spotube-windows-x86_64-setup.exe`, [faWindows], 'exe'],
macOS: [`${nightlyReleaseUrl}/Spotube-macos-universal.dmg`, [faApple], 'dmg'], export const extendedNightlyDownloadLinks: Record<
'Ubuntu, Debian': [`${nightlyReleaseUrl}/Spotube-linux-x86_64.deb`, [faUbuntu, faDebian], 'deb'], string,
'Fedora, Redhat, Opensuse': [ [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`, `${nightlyReleaseUrl}/Spotube-linux-x86_64.rpm`,
[faFedora, faRedhat, faOpensuse], [faFedora, faRedhat, faOpensuse],
'rpm' "rpm",
], ],
iPhone: [`${nightlyReleaseUrl}/Spotube-iOS.ipa`, [faApple], 'ipa'] iPhone: [`${nightlyReleaseUrl}/Spotube-iOS.ipa`, [faApple], "ipa"],
}; };
export const ADS_SLOTS = Object.freeze({
rootPageDisplay: 5979549631,
blogPageInFeed: 3386010031,
downloadPageDisplay: 9521642154,
packagePageArticle: 9119323068,
// This is being used for rehype-auto-ads in svelte.config.js
blogArticlePageArticle: 6788673194,
});

View File

@ -4,6 +4,7 @@ export interface Post {
tags: string[]; tags: string[];
published: boolean; published: boolean;
author: string; author: string;
cover_img: string | null;
readingTime: { readingTime: {
text: string; text: string;
minutes: number; minutes: number;
@ -21,21 +22,23 @@ export interface Post {
export const getPosts = async () => { export const getPosts = async () => {
// Fetch posts from local Markdown files // Fetch posts from local Markdown files
const posts: Post[] = await Promise.all( const posts: Post[] = await Promise.all(
Object.entries(import.meta.glob('../../posts/**/*.md')).map(async ([path, resolver]) => { Object.entries(import.meta.glob("../../posts/**/*.md")).map(
async ([path, resolver]) => {
const resolved = (await resolver()) as { metadata: Post }; const resolved = (await resolver()) as { metadata: Post };
const { metadata } = resolved; const { metadata } = resolved;
const slug = path.split('/').pop()?.slice(0, -3) ?? ''; const slug = path.split("/").pop()?.slice(0, -3) ?? "";
return { ...metadata, slug }; return { ...metadata, slug };
}) },
); ),
).then((posts) => posts.filter((post) => post.published));
let sortedPosts = posts.sort((a, b) => +new Date(b.date) - +new Date(a.date)); let sortedPosts = posts.sort((a, b) => +new Date(b.date) - +new Date(a.date));
sortedPosts = sortedPosts.map((post) => ({ sortedPosts = sortedPosts.map((post) => ({
...post ...post,
})); }));
return { return {
posts: sortedPosts posts: sortedPosts,
}; };
}; };

View File

@ -10,6 +10,8 @@
import { Download, Heart } from 'lucide-svelte'; import { Download, Heart } from 'lucide-svelte';
import type { PageData } from './$types'; import type { PageData } from './$types';
import { Avatar } from '@skeletonlabs/skeleton'; import { Avatar } from '@skeletonlabs/skeleton';
import Ads from '$lib/components/ads/ads.svelte';
import { ADS_SLOTS } from '$lib';
export let data: PageData; export let data: PageData;
@ -75,6 +77,8 @@
</a> </a>
</div> </div>
<Ads adSlot={ADS_SLOTS.rootPageDisplay} adFormat="auto" />
<br /><br /> <br /><br />
<h2 class="h2"> <h2 class="h2">
@ -111,4 +115,5 @@
</a> </a>
{/each} {/each}
</div> </div>
<Ads adSlot={ADS_SLOTS.rootPageDisplay} adFormat="auto" />
</section> </section>

View File

@ -1,4 +1,7 @@
<script lang="ts"> <script lang="ts">
import { ADS_SLOTS } from '$lib';
import Ads from '$lib/components/ads/ads.svelte';
import type { Post } from '$lib/posts';
import type { PageData } from './$types'; import type { PageData } from './$types';
export let data: PageData; export let data: PageData;
@ -6,17 +9,56 @@
const formatter = Intl.DateTimeFormat('en-US', { const formatter = Intl.DateTimeFormat('en-US', {
dateStyle: 'medium' dateStyle: 'medium'
}); });
// insert a special Post as ad type in the posts array
const adAddedPosts: Post[] = [];
for (const post of data.posts) {
adAddedPosts.push(post);
const index = adAddedPosts.indexOf(post);
if (index % 3 === 0) {
adAddedPosts.push({
title: 'Ad',
author: 'Ad',
cover_img: 'ad.jpg',
date: new Date().toISOString(),
path: '/ad',
preview: 'Ad',
preview_html: 'Ad',
previewHtml: 'Ad',
published: true,
reading_time_text: 'Ad',
readingTime: { minutes: 1, words: 1, text: 'Ad', time: 1 },
slug: 'ad',
tags: ['Ad']
});
}
}
</script> </script>
<section class="p-4 md:p-16 flex flex-col gap-4"> <section class="p-4 md:p-16 flex flex-col gap-4">
<h2 class="h2">Blog Posts</h2> <h2 class="h2">Blog Posts</h2>
<br /> <br />
<article class="grid sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4"> <article class="grid sm:grid-cols-2 md:grid-cols-3 2xl:grid-cols-4">
{#each data.posts as post} {#each adAddedPosts as post}
{#if post.slug === 'ad'}
<Ads
adSlot={ADS_SLOTS.blogPageInFeed}
adFormat="fluid"
adLayoutKey="-6l+eh+17-40+59"
fullWidthResponsive={false}
/>
{:else}
<a <a
href={`/blog/${post.slug}`} href={`/blog/${post.slug}`}
class="card hover:brightness-95 active:bg-secondary-hover-token active:scale-95 transition-all variant-ghost-secondary p-4" class="card hover:brightness-95 active:bg-secondary-hover-token active:scale-95 transition-all variant-ghost-secondary p-4"
> >
<img
src={`/posts/${post.cover_img}`}
alt={post.title}
class="rounded h-56 w-full object-cover"
/>
<h4 class="h4">{post.title}</h4> <h4 class="h4">{post.title}</h4>
<p>By {post.author}</p> <p>By {post.author}</p>
<br /> <br />
@ -27,6 +69,7 @@
</span> </span>
</p> </p>
</a> </a>
{/if}
{/each} {/each}
</article> </article>
</section> </section>

View File

@ -1,11 +1,10 @@
import type { Post } from '$lib/posts.js'; import type { Post } from "$lib/posts.js";
export const load = async ({ fetch }) => { export const load = async ({ fetch }) => {
const res = await fetch(`api/posts`); const res = await fetch("api/posts");
if (res.ok) { if (res.ok) {
const posts: Post[] = await res.json(); const posts: Post[] = await res.json();
return { posts }; return { posts };
} else {
return { posts: [] };
} }
return { posts: [] };
}; };

View File

@ -3,9 +3,9 @@
import type { PageData } from './$types'; import type { PageData } from './$types';
export let data: PageData; export let data: PageData;
let { const {
Content, Content,
meta: { date, title, readingTime } meta: { date, title, readingTime, cover_img }
} = data as Required<PageData>; } = data as Required<PageData>;
</script> </script>
@ -14,13 +14,19 @@
</svelte:head> </svelte:head>
<article class="p-4 md:p-16 flex flex-grow flex-col"> <article class="p-4 md:p-16 flex flex-grow flex-col">
<h1 class="h1">{title}</h1> <section
class={cover_img
? 'bg-black/30 h-56 md:h-80 xl:h-96 bg-cover bg-center flex flex-col justify-end p-4 pb-0 md:p-8 md:pb-0 rounded-lg'
: null}
style={cover_img ? `background-image: url(/posts/${cover_img});` : ''}
>
<h1 class={`h1 ${cover_img ? 'text-white' : ''}`}>{title}</h1>
<br />
<p class={cover_img ? 'text-gray-400' : ''}>{new Date(date).toDateString()}</p>
<p class={`mb-16 ${cover_img ? 'text-gray-400' : ''}`}>{readingTime?.text ?? ''}</p>
</section>
<br /> <br />
<div class="">
<p>{new Date(date).toDateString()}</p>
<p class="mb-16">{readingTime?.text ?? ''}</p>
<Layout> <Layout>
<svelte:component this={Content} /> <svelte:component this={Content} />
</Layout> </Layout>
</div>
</article> </article>

View File

@ -1,8 +1,9 @@
<script lang="ts"> <script lang="ts">
import { extendedDownloadLinks } from '$lib'; import { ADS_SLOTS, extendedDownloadLinks } from '$lib';
import { Download } from 'lucide-svelte'; import { Download } from 'lucide-svelte';
import { History, Sparkles, Package } from 'lucide-svelte'; import { History, Sparkles, Package } from 'lucide-svelte';
import DownloadItems from '$lib/components/downloads/download-items.svelte'; import DownloadItems from '$lib/components/downloads/download-items.svelte';
import Ads from '$lib/components/ads/ads.svelte';
const otherDownloads: [string, string, any][] = [ const otherDownloads: [string, string, any][] = [
['/downloads/packages', 'CLI Packages Managers', Package], ['/downloads/packages', 'CLI Packages Managers', Package],
@ -11,7 +12,7 @@
]; ];
</script> </script>
<section class="p-4 md:p-16"> <section class="p-4 md:p-16 md:pb-4">
<h2 class="h2 flex items-center gap-4"> <h2 class="h2 flex items-center gap-4">
Download Download
<Download class="inline" size={30} /> <Download class="inline" size={30} />
@ -22,7 +23,7 @@
<DownloadItems links={extendedDownloadLinks} /> <DownloadItems links={extendedDownloadLinks} />
<br /><br /><br /> <Ads adSlot={ADS_SLOTS.downloadPageDisplay} adFormat="auto" />
<h2 class="h2">Other Downloads</h2> <h2 class="h2">Other Downloads</h2>
<br /><br /> <br /><br />
@ -36,4 +37,5 @@
</a> </a>
{/each} {/each}
</div> </div>
<Ads adSlot={ADS_SLOTS.downloadPageDisplay} adFormat="auto" />
</section> </section>

View File

@ -6,6 +6,8 @@ author: Kingkor Roy Tirtho
<script lang="ts"> <script lang="ts">
import { faLinux, faWindows, faApple } from '@fortawesome/free-brands-svg-icons'; import { faLinux, faWindows, faApple } from '@fortawesome/free-brands-svg-icons';
import Fa from 'svelte-fa'; import Fa from 'svelte-fa';
import Ads from '$lib/components/ads/ads.svelte';
import { ADS_SLOTS } from '$lib';
</script> </script>
<div class="p-4 md:ps-24"> <div class="p-4 md:ps-24">
@ -40,6 +42,14 @@ $ pamac install spotube-bin
$ paru -Sy spotube-bin $ paru -Sy spotube-bin
``` ```
<Ads
style="display:block; text-align:center;"
adSlot={ADS_SLOTS.packagePageArticle}
adLayout="in-article"
adFormat="fluid"
fullWidthResponsive={false}
/>
## <Fa class="inline" icon={faApple} /> MacOS ## <Fa class="inline" icon={faApple} /> MacOS
### Homebrew🍻 ### Homebrew🍻
@ -51,6 +61,14 @@ $ brew tap krtirtho/apps
$ brew install --cask spotube $ brew install --cask spotube
``` ```
<Ads
style="display:block; text-align:center;"
adSlot={ADS_SLOTS.packagePageArticle}
adLayout="in-article"
adFormat="fluid"
fullWidthResponsive={false}
/>
## <Fa class="inline" icon={faWindows} color="#00A2F0" /> Windows ## <Fa class="inline" icon={faWindows} color="#00A2F0" /> Windows
### Chocolatey🍫 ### Chocolatey🍫

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

View File

@ -7,6 +7,7 @@ import slugPlugin from 'rehype-slug';
import autolinkHeadings from 'rehype-autolink-headings'; import autolinkHeadings from 'rehype-autolink-headings';
import relativeImages from 'mdsvex-relative-images'; import relativeImages from 'mdsvex-relative-images';
import remarkGfm from 'remark-gfm'; import remarkGfm from 'remark-gfm';
import rehypeAutoAds from 'rehype-auto-ads';
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
const config = { const config = {
@ -38,6 +39,25 @@ const config = {
{ {
behavior: 'wrap' behavior: 'wrap'
} }
],
[
rehypeAutoAds,
{
adCode: `
<ins class="adsbygoogle"
style="display:block; text-align:center;"
data-ad-layout="in-article"
data-ad-format="fluid"
data-ad-client="ca-pub-6419300932495863"
data-ad-slot="6788673194"
></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
`,
paragraphInterval: 2,
maxAds: 5,
}
] ]
] ]
}) })