mirror of
https://github.com/gabehf/Koito.git
synced 2026-03-14 09:55:55 -07:00
fix: ui fixes and koito import time config fix (#128)
* fix: add import time checking to koito import * adjust interest graph css * show musicbrainz link when not logged in * remove chart animation * change interest steps to 16
This commit is contained in:
parent
231eb1b0fb
commit
ddb0becc0f
3 changed files with 104 additions and 103 deletions
|
|
@ -1,17 +1,8 @@
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import {
|
import { getInterest, type getInterestArgs } from "api/api";
|
||||||
getActivity,
|
|
||||||
getInterest,
|
|
||||||
type getActivityArgs,
|
|
||||||
type getInterestArgs,
|
|
||||||
type ListenActivityItem,
|
|
||||||
} from "api/api";
|
|
||||||
import Popup from "./Popup";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { useTheme } from "~/hooks/useTheme";
|
import { useTheme } from "~/hooks/useTheme";
|
||||||
import ActivityOptsSelector from "./ActivityOptsSelector";
|
|
||||||
import type { Theme } from "~/styles/themes.css";
|
import type { Theme } from "~/styles/themes.css";
|
||||||
import { Area, AreaChart, Line, LineChart, Tooltip } from "recharts";
|
import { Area, AreaChart } from "recharts";
|
||||||
import { RechartsDevtools } from "@recharts/devtools";
|
import { RechartsDevtools } from "@recharts/devtools";
|
||||||
|
|
||||||
function getPrimaryColor(theme: Theme): string {
|
function getPrimaryColor(theme: Theme): string {
|
||||||
|
|
@ -34,7 +25,7 @@ interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function InterestGraph({
|
export default function InterestGraph({
|
||||||
buckets = 14,
|
buckets = 16,
|
||||||
artistId = 0,
|
artistId = 0,
|
||||||
albumId = 0,
|
albumId = 0,
|
||||||
trackId = 0,
|
trackId = 0,
|
||||||
|
|
@ -71,6 +62,10 @@ export default function InterestGraph({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: I would really like to have the animation for the graph, however
|
||||||
|
// the line graph can get weirdly clipped before the animation is done
|
||||||
|
// so I think I just have to remove it for now.
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-start w-full max-w-[500px]">
|
<div className="flex flex-col items-start w-full max-w-[500px]">
|
||||||
<h3>Interest over time</h3>
|
<h3>Interest over time</h3>
|
||||||
|
|
@ -81,13 +76,13 @@ export default function InterestGraph({
|
||||||
maxWidth: 440,
|
maxWidth: 440,
|
||||||
overflow: "visible",
|
overflow: "visible",
|
||||||
}}
|
}}
|
||||||
margin={{ top: 5, right: 0, left: 0, bottom: 10 }}
|
|
||||||
data={data}
|
data={data}
|
||||||
|
margin={{ top: 15, bottom: 20 }}
|
||||||
>
|
>
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id="colorGradient" x1="0" y1="0" x2="0" y2="1">
|
<linearGradient id="colorGradient" x1="0" y1="0" x2="0" y2="1">
|
||||||
<stop offset="5%" stopColor={color} stopOpacity={0.5} />
|
<stop offset="5%" stopColor={color} stopOpacity={0.5} />
|
||||||
<stop offset="85%" stopColor={color} stopOpacity={0} />
|
<stop offset="95%" stopColor={color} stopOpacity={0} />
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
<Area
|
<Area
|
||||||
|
|
@ -95,7 +90,7 @@ export default function InterestGraph({
|
||||||
type="natural"
|
type="natural"
|
||||||
stroke="none"
|
stroke="none"
|
||||||
fill="url(#colorGradient)"
|
fill="url(#colorGradient)"
|
||||||
animationDuration={750}
|
animationDuration={0}
|
||||||
animationEasing="ease-in-out"
|
animationEasing="ease-in-out"
|
||||||
activeDot={false}
|
activeDot={false}
|
||||||
/>
|
/>
|
||||||
|
|
@ -105,11 +100,11 @@ export default function InterestGraph({
|
||||||
stroke={color}
|
stroke={color}
|
||||||
fill="none"
|
fill="none"
|
||||||
strokeWidth={2}
|
strokeWidth={2}
|
||||||
animationDuration={750}
|
animationDuration={0}
|
||||||
animationEasing="ease-in-out"
|
animationEasing="ease-in-out"
|
||||||
dot={false}
|
dot={false}
|
||||||
activeDot={false}
|
activeDot={false}
|
||||||
style={{ filter: `drop-shadow(0px 0px 5px ${color})` }}
|
style={{ filter: `drop-shadow(0px 0px 0px ${color})` }}
|
||||||
/>
|
/>
|
||||||
</AreaChart>
|
</AreaChart>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -99,97 +99,99 @@ export default function MediaLayout(props: Props) {
|
||||||
<h1>{props.title}</h1>
|
<h1>{props.title}</h1>
|
||||||
{props.subContent}
|
{props.subContent}
|
||||||
</div>
|
</div>
|
||||||
{user && (
|
<div className="absolute left-1 sm:right-1 sm:left-auto -top-9 sm:top-1 flex gap-3 items-center">
|
||||||
<div className="absolute left-1 sm:right-1 sm:left-auto -top-9 sm:top-1 flex gap-3 items-center">
|
{props.musicbrainzId && (
|
||||||
{props.musicbrainzId && (
|
<Link
|
||||||
<Link
|
title="View on MusicBrainz"
|
||||||
title="View on MusicBrainz"
|
target="_blank"
|
||||||
target="_blank"
|
to={`https://musicbrainz.org/${props.type.toLowerCase()}/${
|
||||||
to={`https://musicbrainz.org/${props.type.toLowerCase()}/${
|
props.musicbrainzId
|
||||||
props.musicbrainzId
|
}`}
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<MbzIcon size={iconSize} hover />
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
{props.type === "Track" && (
|
|
||||||
<>
|
|
||||||
<button
|
|
||||||
title="Add Listen"
|
|
||||||
className="hover:cursor-pointer"
|
|
||||||
onClick={() => setAddListenModalOpen(true)}
|
|
||||||
>
|
|
||||||
<Plus size={iconSize} />
|
|
||||||
</button>
|
|
||||||
<AddListenModal
|
|
||||||
open={addListenModalOpen}
|
|
||||||
setOpen={setAddListenModalOpen}
|
|
||||||
trackid={props.id}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<button
|
|
||||||
title="Edit Item"
|
|
||||||
className="hover:cursor-pointer"
|
|
||||||
onClick={() => setRenameModalOpen(true)}
|
|
||||||
>
|
>
|
||||||
<Edit size={iconSize} />
|
<MbzIcon size={iconSize} hover />
|
||||||
</button>
|
</Link>
|
||||||
|
)}
|
||||||
{props.type !== "Track" && (
|
{user && (
|
||||||
|
<>
|
||||||
|
{props.type === "Track" && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
title="Add Listen"
|
||||||
|
className="hover:cursor-pointer"
|
||||||
|
onClick={() => setAddListenModalOpen(true)}
|
||||||
|
>
|
||||||
|
<Plus size={iconSize} />
|
||||||
|
</button>
|
||||||
|
<AddListenModal
|
||||||
|
open={addListenModalOpen}
|
||||||
|
setOpen={setAddListenModalOpen}
|
||||||
|
trackid={props.id}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<button
|
<button
|
||||||
title="Replace Image"
|
title="Edit Item"
|
||||||
className="hover:cursor-pointer"
|
className="hover:cursor-pointer"
|
||||||
onClick={() => setImageModalOpen(true)}
|
onClick={() => setRenameModalOpen(true)}
|
||||||
>
|
>
|
||||||
<ImageIcon size={iconSize} />
|
<Edit size={iconSize} />
|
||||||
</button>
|
</button>
|
||||||
)}
|
|
||||||
<button
|
{props.type !== "Track" && (
|
||||||
title="Merge Items"
|
<button
|
||||||
className="hover:cursor-pointer"
|
title="Replace Image"
|
||||||
onClick={() => setMergeModalOpen(true)}
|
className="hover:cursor-pointer"
|
||||||
>
|
onClick={() => setImageModalOpen(true)}
|
||||||
<Merge size={iconSize} />
|
>
|
||||||
</button>
|
<ImageIcon size={iconSize} />
|
||||||
<button
|
</button>
|
||||||
title="Delete Item"
|
)}
|
||||||
className="hover:cursor-pointer"
|
<button
|
||||||
onClick={() => setDeleteModalOpen(true)}
|
title="Merge Items"
|
||||||
>
|
className="hover:cursor-pointer"
|
||||||
<Trash size={iconSize} />
|
onClick={() => setMergeModalOpen(true)}
|
||||||
</button>
|
>
|
||||||
<EditModal
|
<Merge size={iconSize} />
|
||||||
open={renameModalOpen}
|
</button>
|
||||||
setOpen={setRenameModalOpen}
|
<button
|
||||||
type={props.type.toLowerCase()}
|
title="Delete Item"
|
||||||
id={props.id}
|
className="hover:cursor-pointer"
|
||||||
/>
|
onClick={() => setDeleteModalOpen(true)}
|
||||||
<ImageReplaceModal
|
>
|
||||||
open={imageModalOpen}
|
<Trash size={iconSize} />
|
||||||
setOpen={setImageModalOpen}
|
</button>
|
||||||
id={props.imgItemId}
|
<EditModal
|
||||||
musicbrainzId={props.musicbrainzId}
|
open={renameModalOpen}
|
||||||
type={props.type === "Track" ? "Album" : props.type}
|
setOpen={setRenameModalOpen}
|
||||||
/>
|
type={props.type.toLowerCase()}
|
||||||
<MergeModal
|
id={props.id}
|
||||||
currentTitle={props.title}
|
/>
|
||||||
mergeFunc={props.mergeFunc}
|
<ImageReplaceModal
|
||||||
mergeCleanerFunc={props.mergeCleanerFunc}
|
open={imageModalOpen}
|
||||||
type={props.type}
|
setOpen={setImageModalOpen}
|
||||||
currentId={props.id}
|
id={props.imgItemId}
|
||||||
open={mergeModalOpen}
|
musicbrainzId={props.musicbrainzId}
|
||||||
setOpen={setMergeModalOpen}
|
type={props.type === "Track" ? "Album" : props.type}
|
||||||
/>
|
/>
|
||||||
<DeleteModal
|
<MergeModal
|
||||||
open={deleteModalOpen}
|
currentTitle={props.title}
|
||||||
setOpen={setDeleteModalOpen}
|
mergeFunc={props.mergeFunc}
|
||||||
title={props.title}
|
mergeCleanerFunc={props.mergeCleanerFunc}
|
||||||
id={props.id}
|
type={props.type}
|
||||||
type={props.type}
|
currentId={props.id}
|
||||||
/>
|
open={mergeModalOpen}
|
||||||
</div>
|
setOpen={setMergeModalOpen}
|
||||||
)}
|
/>
|
||||||
|
<DeleteModal
|
||||||
|
open={deleteModalOpen}
|
||||||
|
setOpen={setDeleteModalOpen}
|
||||||
|
title={props.title}
|
||||||
|
id={props.id}
|
||||||
|
type={props.type}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{props.children}
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,10 @@ func ImportKoitoFile(ctx context.Context, store db.DB, filename string) error {
|
||||||
count := 0
|
count := 0
|
||||||
|
|
||||||
for i := range data.Listens {
|
for i := range data.Listens {
|
||||||
|
if !inImportTimeWindow(data.Listens[i].ListenedAt) {
|
||||||
|
l.Debug().Msgf("Skipping import due to import time rules")
|
||||||
|
continue
|
||||||
|
}
|
||||||
// use this for save/get mbid for all artist/album/track
|
// use this for save/get mbid for all artist/album/track
|
||||||
var mbid uuid.UUID
|
var mbid uuid.UUID
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue