v7.0.6
This commit is contained in:
+17
-1
@@ -714,6 +714,17 @@ func FilterTrack(data map[string]interface{}, albumFetchData ...map[string]inter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if albumArtistsString == "" {
|
||||||
|
albumArtists := extractArtists(getMap(albumData, "artists"))
|
||||||
|
if len(albumArtists) > 0 {
|
||||||
|
albumArtistNames := []string{}
|
||||||
|
for _, artist := range albumArtists {
|
||||||
|
albumArtistNames = append(albumArtistNames, getString(artist, "name"))
|
||||||
|
}
|
||||||
|
albumArtistsString = strings.Join(albumArtistNames, ", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
albumInfo = map[string]interface{}{
|
albumInfo = map[string]interface{}{
|
||||||
"id": albumID,
|
"id": albumID,
|
||||||
"name": getString(albumData, "name"),
|
"name": getString(albumData, "name"),
|
||||||
@@ -1228,6 +1239,11 @@ func extractDiscographyItems(itemsData map[string]interface{}) []map[string]inte
|
|||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stripHTMLTags(s string) string {
|
||||||
|
re := regexp.MustCompile(`<[^>]*>`)
|
||||||
|
return re.ReplaceAllString(s, "")
|
||||||
|
}
|
||||||
|
|
||||||
func FilterArtist(data map[string]interface{}) map[string]interface{} {
|
func FilterArtist(data map[string]interface{}) map[string]interface{} {
|
||||||
dataMap := getMap(data, "data")
|
dataMap := getMap(data, "data")
|
||||||
artistData := getMap(dataMap, "artistUnion")
|
artistData := getMap(dataMap, "artistUnion")
|
||||||
@@ -1243,7 +1259,7 @@ func FilterArtist(data map[string]interface{}) map[string]interface{} {
|
|||||||
if ok {
|
if ok {
|
||||||
biographyText := getString(biographyMap, "text")
|
biographyText := getString(biographyMap, "text")
|
||||||
if biographyText != "" {
|
if biographyText != "" {
|
||||||
profile["biography"] = html.UnescapeString(biographyText)
|
profile["biography"] = html.UnescapeString(stripHTMLTags(biographyText))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
export const langColors: Record<string, string> = {
|
||||||
|
"TypeScript": "#2b7489",
|
||||||
|
"Go": "#375eab",
|
||||||
|
"Python": "#3572A5",
|
||||||
|
"CSS": "#563d7c",
|
||||||
|
"HTML": "#e44b23",
|
||||||
|
"JavaScript": "#f1e05a",
|
||||||
|
"Java": "#b07219",
|
||||||
|
"C": "#555555",
|
||||||
|
"C Sharp": "#178600",
|
||||||
|
"cpp": "#f34b7d",
|
||||||
|
"Ruby": "#701516",
|
||||||
|
"PHP": "#4F5D95",
|
||||||
|
"Swift": "#ffac45",
|
||||||
|
"Kotlin": "#F18E33",
|
||||||
|
"Rust": "#dea584",
|
||||||
|
"Shell": "#89e051"
|
||||||
|
};
|
||||||
@@ -8,11 +8,12 @@ import { Label } from "@/components/ui/label";
|
|||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
||||||
import { Bug, Lightbulb, ExternalLink } from "lucide-react";
|
import { Bug, Lightbulb, ExternalLink, Star, GitFork, Clock, Download } from "lucide-react";
|
||||||
import ExyezedIcon from "@/assets/icons/exyezed.svg";
|
import ExyezedIcon from "@/assets/icons/exyezed.svg";
|
||||||
import SpotubeDLIcon from "@/assets/icons/spotubedl.svg";
|
import SpotubeDLIcon from "@/assets/icons/spotubedl.svg";
|
||||||
import SpotiDownloaderIcon from "@/assets/icons/spotidownloader.svg";
|
import SpotiDownloaderIcon from "@/assets/icons/spotidownloader.svg";
|
||||||
import XBatchDLIcon from "@/assets/icons/xbatchdl.svg";
|
import XBatchDLIcon from "@/assets/icons/xbatchdl.svg";
|
||||||
|
import { langColors } from "@/assets/github-lang-colors";
|
||||||
interface AboutPageProps {
|
interface AboutPageProps {
|
||||||
version: string;
|
version: string;
|
||||||
}
|
}
|
||||||
@@ -27,6 +28,7 @@ export function AboutPage({ version }: AboutPageProps) {
|
|||||||
const [featureDesc, setFeatureDesc] = useState("");
|
const [featureDesc, setFeatureDesc] = useState("");
|
||||||
const [useCase, setUseCase] = useState("");
|
const [useCase, setUseCase] = useState("");
|
||||||
const [featureContext, setFeatureContext] = useState("");
|
const [featureContext, setFeatureContext] = useState("");
|
||||||
|
const [repoStats, setRepoStats] = useState<Record<string, any>>({});
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchOS = async () => {
|
const fetchOS = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -66,6 +68,80 @@ export function AboutPage({ version }: AboutPageProps) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
fetchLocation();
|
fetchLocation();
|
||||||
|
const fetchRepoStats = async () => {
|
||||||
|
const CACHE_KEY = 'github_repo_stats';
|
||||||
|
const CACHE_DURATION = 1000 * 60 * 60;
|
||||||
|
const cached = localStorage.getItem(CACHE_KEY);
|
||||||
|
if (cached) {
|
||||||
|
try {
|
||||||
|
const { data, timestamp } = JSON.parse(cached);
|
||||||
|
if (Date.now() - timestamp < CACHE_DURATION) {
|
||||||
|
setRepoStats(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.error('Failed to parse cache:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const repos = [
|
||||||
|
{ name: 'SpotiDownloader', owner: 'afkarxyz' },
|
||||||
|
{ name: 'Twitter-X-Media-Batch-Downloader', owner: 'afkarxyz' }
|
||||||
|
];
|
||||||
|
const stats: Record<string, any> = {};
|
||||||
|
for (const repo of repos) {
|
||||||
|
try {
|
||||||
|
const [repoRes, releasesRes, langsRes] = await Promise.all([
|
||||||
|
fetch(`https://api.github.com/repos/${repo.owner}/${repo.name}`),
|
||||||
|
fetch(`https://api.github.com/repos/${repo.owner}/${repo.name}/releases`),
|
||||||
|
fetch(`https://api.github.com/repos/${repo.owner}/${repo.name}/languages`)
|
||||||
|
]);
|
||||||
|
if (repoRes.status === 403) {
|
||||||
|
if (cached) {
|
||||||
|
const { data } = JSON.parse(cached);
|
||||||
|
setRepoStats(data);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (repoRes.ok && releasesRes.ok && langsRes.ok) {
|
||||||
|
const repoData = await repoRes.json();
|
||||||
|
const releases = await releasesRes.json();
|
||||||
|
const languages = await langsRes.json();
|
||||||
|
let totalDownloads = 0;
|
||||||
|
let latestDownloads = 0;
|
||||||
|
if (releases.length > 0) {
|
||||||
|
latestDownloads = releases[0].assets?.reduce((sum: number, asset: any) => sum + (asset.download_count || 0), 0) || 0;
|
||||||
|
totalDownloads = releases.reduce((sum: number, release: any) => {
|
||||||
|
return sum + (release.assets?.reduce((s: number, a: any) => s + (a.download_count || 0), 0) || 0);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
const topLangs = Object.entries(languages)
|
||||||
|
.sort(([, a]: any, [, b]: any) => b - a)
|
||||||
|
.slice(0, 4)
|
||||||
|
.map(([lang]) => lang);
|
||||||
|
stats[repo.name] = {
|
||||||
|
stars: repoData.stargazers_count,
|
||||||
|
forks: repoData.forks_count,
|
||||||
|
createdAt: repoData.created_at,
|
||||||
|
totalDownloads,
|
||||||
|
latestDownloads,
|
||||||
|
languages: topLangs
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.error(`Failed to fetch stats for ${repo.name}:`, err);
|
||||||
|
if (cached) {
|
||||||
|
const { data } = JSON.parse(cached);
|
||||||
|
setRepoStats(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setRepoStats(stats);
|
||||||
|
localStorage.setItem(CACHE_KEY, JSON.stringify({ data: stats, timestamp: Date.now() }));
|
||||||
|
};
|
||||||
|
fetchRepoStats();
|
||||||
}, []);
|
}, []);
|
||||||
const faqs = [
|
const faqs = [
|
||||||
{
|
{
|
||||||
@@ -92,6 +168,34 @@ export function AboutPage({ version }: AboutPageProps) {
|
|||||||
const sanitizeForURL = (text: string): string => {
|
const sanitizeForURL = (text: string): string => {
|
||||||
return text.replace(/[()]/g, "").replace(/,/g, " -");
|
return text.replace(/[()]/g, "").replace(/,/g, " -");
|
||||||
};
|
};
|
||||||
|
const formatTimeAgo = (dateString: string): string => {
|
||||||
|
const now = new Date();
|
||||||
|
const updated = new Date(dateString);
|
||||||
|
const diffMs = now.getTime() - updated.getTime();
|
||||||
|
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
||||||
|
const diffMonths = Math.floor(diffDays / 30);
|
||||||
|
if (diffDays === 0)
|
||||||
|
return 'today';
|
||||||
|
if (diffDays === 1)
|
||||||
|
return '1d';
|
||||||
|
if (diffDays < 30)
|
||||||
|
return `${diffDays}d`;
|
||||||
|
if (diffMonths === 1)
|
||||||
|
return '1mo';
|
||||||
|
if (diffMonths < 12)
|
||||||
|
return `${diffMonths}mo`;
|
||||||
|
const diffYears = Math.floor(diffMonths / 12);
|
||||||
|
return `${diffYears}y`;
|
||||||
|
};
|
||||||
|
const formatNumber = (num: number): string => {
|
||||||
|
if (num >= 1000) {
|
||||||
|
return num.toLocaleString();
|
||||||
|
}
|
||||||
|
return num.toString();
|
||||||
|
};
|
||||||
|
const getLangColor = (lang: string): string => {
|
||||||
|
return langColors[lang] || '#858585';
|
||||||
|
};
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
let title = "";
|
let title = "";
|
||||||
let body = "";
|
let body = "";
|
||||||
@@ -256,12 +360,40 @@ ${location || "Unknown"}
|
|||||||
<CardTitle className="flex items-center gap-2"><img src={SpotiDownloaderIcon} className="h-5 w-5" alt="SpotiDownloader" /> SpotiDownloader</CardTitle>
|
<CardTitle className="flex items-center gap-2"><img src={SpotiDownloaderIcon} className="h-5 w-5" alt="SpotiDownloader" /> SpotiDownloader</CardTitle>
|
||||||
<CardDescription>Get Spotify tracks in MP3 and FLAC via the spotidownloader.com API.</CardDescription>
|
<CardDescription>Get Spotify tracks in MP3 and FLAC via the spotidownloader.com API.</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
{repoStats['SpotiDownloader'] && (<CardContent className="space-y-3">
|
||||||
|
<div className="flex flex-wrap gap-2 text-xs">
|
||||||
|
{repoStats['SpotiDownloader'].languages?.map((lang: string) => (<span key={lang} className="px-2 py-0.5 rounded-full font-medium" style={{ backgroundColor: getLangColor(lang) + '20', color: getLangColor(lang) }}>{lang}</span>))}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-4 text-xs text-muted-foreground">
|
||||||
|
<span className="flex items-center gap-1"><Star className="h-3.5 w-3.5 fill-amber-500 text-amber-500" /> {formatNumber(repoStats['SpotiDownloader'].stars)}</span>
|
||||||
|
<span className="flex items-center gap-1"><GitFork className="h-3.5 w-3.5" /> {repoStats['SpotiDownloader'].forks}</span>
|
||||||
|
<span className="flex items-center gap-1"><Clock className="h-3.5 w-3.5" /> {formatTimeAgo(repoStats['SpotiDownloader'].createdAt)}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-4 text-xs text-muted-foreground">
|
||||||
|
<span className="flex items-center gap-1"><Download className="h-3.5 w-3.5" /> TOTAL: {formatNumber(repoStats['SpotiDownloader'].totalDownloads)}</span>
|
||||||
|
<span className="flex items-center gap-1 text-green-600 dark:text-green-400"><Download className="h-3.5 w-3.5" /> LATEST: {formatNumber(repoStats['SpotiDownloader'].latestDownloads)}</span>
|
||||||
|
</div>
|
||||||
|
</CardContent>)}
|
||||||
</Card>
|
</Card>
|
||||||
<Card className="hover:bg-muted/50 hover:border-primary/50 transition-colors cursor-pointer" onClick={() => openExternal("https://github.com/afkarxyz/Twitter-X-Media-Batch-Downloader")}>
|
<Card className="hover:bg-muted/50 hover:border-primary/50 transition-colors cursor-pointer" onClick={() => openExternal("https://github.com/afkarxyz/Twitter-X-Media-Batch-Downloader")}>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="flex items-center gap-2"><img src={XBatchDLIcon} className="h-5 w-5" alt="Twitter/X Media Batch Downloader" /> Twitter/X Batch Downloader</CardTitle>
|
<CardTitle className="flex items-center gap-2"><img src={XBatchDLIcon} className="h-5 w-5" alt="Twitter/X Media Batch Downloader" /> Twitter/X Media Batch Downloader</CardTitle>
|
||||||
<CardDescription>A GUI tool to download original-quality images and videos from Twitter/X accounts, powered by gallery-dl by @mikf</CardDescription>
|
<CardDescription>A GUI tool to download original-quality images and videos from Twitter/X accounts, powered by gallery-dl by @mikf</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
{repoStats['Twitter-X-Media-Batch-Downloader'] && (<CardContent className="space-y-3">
|
||||||
|
<div className="flex flex-wrap gap-2 text-xs">
|
||||||
|
{repoStats['Twitter-X-Media-Batch-Downloader'].languages?.map((lang: string) => (<span key={lang} className="px-2 py-0.5 rounded-full font-medium" style={{ backgroundColor: getLangColor(lang) + '20', color: getLangColor(lang) }}>{lang}</span>))}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-4 text-xs text-muted-foreground">
|
||||||
|
<span className="flex items-center gap-1"><Star className="h-3.5 w-3.5 fill-amber-500 text-amber-500" /> {formatNumber(repoStats['Twitter-X-Media-Batch-Downloader'].stars)}</span>
|
||||||
|
<span className="flex items-center gap-1"><GitFork className="h-3.5 w-3.5" /> {repoStats['Twitter-X-Media-Batch-Downloader'].forks}</span>
|
||||||
|
<span className="flex items-center gap-1"><Clock className="h-3.5 w-3.5" /> {formatTimeAgo(repoStats['Twitter-X-Media-Batch-Downloader'].createdAt)}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-4 text-xs text-muted-foreground">
|
||||||
|
<span className="flex items-center gap-1"><Download className="h-3.5 w-3.5" /> TOTAL: {formatNumber(repoStats['Twitter-X-Media-Batch-Downloader'].totalDownloads)}</span>
|
||||||
|
<span className="flex items-center gap-1 text-green-600 dark:text-green-400"><Download className="h-3.5 w-3.5" /> LATEST: {formatNumber(repoStats['Twitter-X-Media-Batch-Downloader'].latestDownloads)}</span>
|
||||||
|
</div>
|
||||||
|
</CardContent>)}
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|||||||
@@ -209,8 +209,10 @@ export function HistoryPage() {
|
|||||||
</td>
|
</td>
|
||||||
<td className="p-3 align-middle text-left hidden lg:table-cell">
|
<td className="p-3 align-middle text-left hidden lg:table-cell">
|
||||||
<div className="flex flex-col items-start gap-1">
|
<div className="flex flex-col items-start gap-1">
|
||||||
<span className="text-[10px] font-bold text-foreground">{item.format}</span>
|
<span className="text-xs font-bold text-foreground">
|
||||||
{item.quality && <span className="text-[9px] text-muted-foreground leading-none whitespace-nowrap">{item.quality}</span>}
|
{['HI_RES_LOSSLESS', 'LOSSLESS'].includes(item.format) ? 'FLAC' : item.format}
|
||||||
|
</span>
|
||||||
|
{item.quality && <span className="text-[11px] text-muted-foreground leading-none whitespace-nowrap">{item.quality}</span>}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-3 align-middle text-sm text-muted-foreground text-left hidden xl:table-cell font-mono">
|
<td className="p-3 align-middle text-sm text-muted-foreground text-left hidden xl:table-cell font-mono">
|
||||||
@@ -229,7 +231,8 @@ export function HistoryPage() {
|
|||||||
</table>)}
|
</table>)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{totalPages > 1 && (<Pagination>
|
{
|
||||||
|
totalPages > 1 && (<Pagination>
|
||||||
<PaginationContent>
|
<PaginationContent>
|
||||||
<PaginationItem>
|
<PaginationItem>
|
||||||
<PaginationPrevious href="#" onClick={(e) => {
|
<PaginationPrevious href="#" onClick={(e) => {
|
||||||
@@ -258,7 +261,8 @@ export function HistoryPage() {
|
|||||||
}} className={currentPage === totalPages ? "pointer-events-none opacity-50" : "cursor-pointer"} />
|
}} className={currentPage === totalPages ? "pointer-events-none opacity-50" : "cursor-pointer"} />
|
||||||
</PaginationItem>
|
</PaginationItem>
|
||||||
</PaginationContent>
|
</PaginationContent>
|
||||||
</Pagination>)}
|
</Pagination>)
|
||||||
|
}
|
||||||
|
|
||||||
<Dialog open={showClearConfirm} onOpenChange={setShowClearConfirm}>
|
<Dialog open={showClearConfirm} onOpenChange={setShowClearConfirm}>
|
||||||
<DialogContent className="max-w-md [&>button]:hidden">
|
<DialogContent className="max-w-md [&>button]:hidden">
|
||||||
|
|||||||
@@ -266,40 +266,40 @@ export function SettingsPage({ onUnsavedChangesChange, onResetRequest }: Setting
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="tidal-qobuz">
|
<SelectItem value="tidal-qobuz">
|
||||||
<span className="flex items-center gap-1.5"><TidalIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><QobuzIcon className="fill-white"/></span>
|
<span className="flex items-center gap-1.5"><TidalIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><QobuzIcon className="fill-current"/></span>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem value="tidal-amazon">
|
<SelectItem value="tidal-amazon">
|
||||||
<span className="flex items-center gap-1.5"><TidalIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><AmazonIcon className="fill-white"/></span>
|
<span className="flex items-center gap-1.5"><TidalIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><AmazonIcon className="fill-current"/></span>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem value="qobuz-tidal">
|
<SelectItem value="qobuz-tidal">
|
||||||
<span className="flex items-center gap-1.5"><QobuzIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><TidalIcon className="fill-white"/></span>
|
<span className="flex items-center gap-1.5"><QobuzIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><TidalIcon className="fill-current"/></span>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem value="qobuz-amazon">
|
<SelectItem value="qobuz-amazon">
|
||||||
<span className="flex items-center gap-1.5"><QobuzIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><AmazonIcon className="fill-white"/></span>
|
<span className="flex items-center gap-1.5"><QobuzIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><AmazonIcon className="fill-current"/></span>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem value="amazon-tidal">
|
<SelectItem value="amazon-tidal">
|
||||||
<span className="flex items-center gap-1.5"><AmazonIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><TidalIcon className="fill-white"/></span>
|
<span className="flex items-center gap-1.5"><AmazonIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><TidalIcon className="fill-current"/></span>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem value="amazon-qobuz">
|
<SelectItem value="amazon-qobuz">
|
||||||
<span className="flex items-center gap-1.5"><AmazonIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><QobuzIcon className="fill-white"/></span>
|
<span className="flex items-center gap-1.5"><AmazonIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><QobuzIcon className="fill-current"/></span>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem value="tidal-qobuz-amazon">
|
<SelectItem value="tidal-qobuz-amazon">
|
||||||
<span className="flex items-center gap-1.5"><TidalIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><QobuzIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><AmazonIcon className="fill-white"/></span>
|
<span className="flex items-center gap-1.5"><TidalIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><QobuzIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><AmazonIcon className="fill-current"/></span>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem value="tidal-amazon-qobuz">
|
<SelectItem value="tidal-amazon-qobuz">
|
||||||
<span className="flex items-center gap-1.5"><TidalIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><AmazonIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><QobuzIcon className="fill-white"/></span>
|
<span className="flex items-center gap-1.5"><TidalIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><AmazonIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><QobuzIcon className="fill-current"/></span>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem value="qobuz-tidal-amazon">
|
<SelectItem value="qobuz-tidal-amazon">
|
||||||
<span className="flex items-center gap-1.5"><QobuzIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><TidalIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><AmazonIcon className="fill-white"/></span>
|
<span className="flex items-center gap-1.5"><QobuzIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><TidalIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><AmazonIcon className="fill-current"/></span>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem value="qobuz-amazon-tidal">
|
<SelectItem value="qobuz-amazon-tidal">
|
||||||
<span className="flex items-center gap-1.5"><QobuzIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><AmazonIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><TidalIcon className="fill-white"/></span>
|
<span className="flex items-center gap-1.5"><QobuzIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><AmazonIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><TidalIcon className="fill-current"/></span>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem value="amazon-tidal-qobuz">
|
<SelectItem value="amazon-tidal-qobuz">
|
||||||
<span className="flex items-center gap-1.5"><AmazonIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><TidalIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><QobuzIcon className="fill-white"/></span>
|
<span className="flex items-center gap-1.5"><AmazonIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><TidalIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><QobuzIcon className="fill-current"/></span>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
<SelectItem value="amazon-qobuz-tidal">
|
<SelectItem value="amazon-qobuz-tidal">
|
||||||
<span className="flex items-center gap-1.5"><AmazonIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><QobuzIcon className="fill-white"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><TidalIcon className="fill-white"/></span>
|
<span className="flex items-center gap-1.5"><AmazonIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><QobuzIcon className="fill-current"/><ArrowRight className="h-3 w-3 text-muted-foreground"/><TidalIcon className="fill-current"/></span>
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
|||||||
Reference in New Issue
Block a user