Skip to content

Commit

Permalink
Add tool to get approximate account creation dates
Browse files Browse the repository at this point in the history
Closes #2.
  • Loading branch information
rojvv committed Apr 11, 2024
1 parent 15bad77 commit 3808568
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 7 deletions.
18 changes: 18 additions & 0 deletions components/icons/Clock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export function Clock() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
viewBox="0 0 24 24"
>
<circle cx="12" cy="12" r="10" />
<path d="M12 6v6l4 2" />
</svg>
);
}
4 changes: 3 additions & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
"clsx": "https://esm.sh/clsx@2.1.0",
"tailwind-merge": "https://esm.sh/tailwind-merge@2.2.1",
"esbuild/": "https://deno.land/x/esbuild@v0.20.1/",
"esbuild_deno_loader/": "https://deno.land/x/esbuild_deno_loader@0.8.5/"
"esbuild_deno_loader/": "https://deno.land/x/esbuild_deno_loader@0.8.5/",
"ml-regression-polynomial": "https://esm.sh/ml-regression-polynomial@3.0.0",
"time_ago/": "https://deno.land/x/time_ago@v1/"
},
"compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "preact" }
}
4 changes: 4 additions & 0 deletions fresh.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as $_404 from "./routes/_404.tsx";
import * as $_app from "./routes/_app.tsx";
import * as $_middleware from "./routes/_middleware.tsx";
import * as $connectivity_test from "./routes/connectivity-test.tsx";
import * as $creation_date from "./routes/creation-date.tsx";
import * as $disclaimer from "./routes/disclaimer.tsx";
import * as $file_id_analyzer from "./routes/file-id-analyzer.tsx";
import * as $filter_query_browser from "./routes/filter-query-browser.tsx";
Expand All @@ -21,6 +22,7 @@ import * as $Alert from "./islands/Alert.tsx";
import * as $Confirmation from "./islands/Confirmation.tsx";
import * as $ConnectivityTest from "./islands/ConnectivityTest.tsx";
import * as $CookieNotice from "./islands/CookieNotice.tsx";
import * as $CreationDate from "./islands/CreationDate.tsx";
import * as $FileIdAnalyzer from "./islands/FileIdAnalyzer.tsx";
import * as $FilterQueryBrowser from "./islands/FilterQueryBrowser.tsx";
import * as $InlineMessageIdUnpacker from "./islands/InlineMessageIdUnpacker.tsx";
Expand All @@ -38,6 +40,7 @@ const manifest = {
"./routes/_app.tsx": $_app,
"./routes/_middleware.tsx": $_middleware,
"./routes/connectivity-test.tsx": $connectivity_test,
"./routes/creation-date.tsx": $creation_date,
"./routes/disclaimer.tsx": $disclaimer,
"./routes/file-id-analyzer.tsx": $file_id_analyzer,
"./routes/filter-query-browser.tsx": $filter_query_browser,
Expand All @@ -55,6 +58,7 @@ const manifest = {
"./islands/Confirmation.tsx": $Confirmation,
"./islands/ConnectivityTest.tsx": $ConnectivityTest,
"./islands/CookieNotice.tsx": $CookieNotice,
"./islands/CreationDate.tsx": $CreationDate,
"./islands/FileIdAnalyzer.tsx": $FileIdAnalyzer,
"./islands/FilterQueryBrowser.tsx": $FilterQueryBrowser,
"./islands/InlineMessageIdUnpacker.tsx": $InlineMessageIdUnpacker,
Expand Down
65 changes: 65 additions & 0 deletions islands/CreationDate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { ComponentChildren } from "preact";
import { signal, useSignalEffect } from "@preact/signals";

import { getHashSignal } from "../lib/hash.ts";
import { setHash } from "../lib/hash.ts";

import { Caption } from "../components/Caption.tsx";
import { Input } from "../components/Input.tsx";
import { Label } from "../components/Label.tsx";
import { timeAgo } from "time_ago/mod.ts";
import { predictCreationDate } from "../lib/creation_date.ts";

const hash = getHashSignal();
const getId = () => decodeURIComponent(hash.value.slice(1));

const data = signal<Date | null>(null);

export function CreationDate() {
const id = getId();

useSignalEffect(() => {
const id = Number(getId());
if (isNaN(id) || !id) {
data.value = null
return;
}

data.value = predictCreationDate(id);
});

return (
<div class="w-full mx-auto max-w-lg gap-5 flex flex-col items-center text-center">
<div class={"flex flex-col gap-0.5 "}>
<div class={`font-bold text-xs ${id.length ? 'opacity-1' :'opacity-0'}`}>User ID</div>
<input
class="select-text text-ellipsis overflow-hidden focus:outline-none text-center bg-transparent placeholder:(text-foreground opacity-[.55]) text-lg"
placeholder="Enter User ID"
value={id}
onKeyUp={(e) => setHash("#" + e.currentTarget.value)}
onKeyPress={(e) => setHash("#" + e.currentTarget.value)}
/>
</div>
{data.value && (
<div class="flex flex-col">
<Kv
k="Creation Date"
v={`${data.value.toDateString()} (${timeAgo(data.value)})`}
/>
<div class="opacity-50 text-xs pt-0.5">
Note: This is an estimate.
</div>
</div>
)}
</div>
);
}

function Kv({ k, v, c }: { k: string; v: ComponentChildren; c?: string }) { // TODO: merge with FileIdAnalyzer's
return (
<div class={"flex flex-col gap-0.5 " + (c ?? "")}>
<div class="font-bold text-xs">{k}</div>
<div class="select-text text-ellipsis overflow-hidden text-lg">{v}</div>
</div>
);
}
54 changes: 54 additions & 0 deletions lib/creation_date.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { PolynomialRegression } from "ml-regression-polynomial";

const entries = [
[1247_000_000, 1587375629],
[1111_000_000, 1582941722],
[1097_000_000, 1582423322],
[1000_000_000, 1571097600],
[989_000_000, 1579917722],
[915_000_000, 1582596122],
[909_000_000, 1568858522],
[850_000_000, 1557878400],
[755_000_000, 1548028800],
[782_000_000, 1546300800],
[728_000_000, 1543708800],
[617_000_000, 1529625600],
[539_000_000, 1515179434],
[495_000_000, 1512846634],
[400_000_000, 1499904000],
[392_000_000, 1509926400],
[370_000_000, 1492214400],
[257_000_000, 1481767322],
[234_000_000, 1464825600],
[200_000_000, 1451606400],
[150_000_000, 1434326400],
[100_000_000, 1429125034],
[55_000_000, 1408129834],
[10_000_000, 1413331200],
[7_679_610, 1389744000],
[2_768_409, 1383264000],
[1_000_000, 1380326400],
[100_000, 1375729834],
[1_000, 1373051434],
[1, 1373051434],
] as [number, number][];

const x = entries.map((v) => v[0]);
const y = entries.map((v) => v[1]);
const regression = new PolynomialRegression(x, y, 5);

export function predictCreationDate(id: number) {
const r = regression.predict(id);
if (r <= 0) return now();
const d = new Date(r * 1_000);
if (isNaN(d.getHours())) return now();
return d;
}
function now() {
const d = new Date();
d.setHours(0);
d.setMinutes(0);
d.setSeconds(0);
d.setMilliseconds(0);
return d;
}
3 changes: 3 additions & 0 deletions routes/creation-date.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { CreationDate } from "../islands/CreationDate.tsx";

export default () => <CreationDate />;
25 changes: 19 additions & 6 deletions routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Card } from "../components/Card.tsx";
import { File } from "../components/icons/File.tsx";
import { At } from "../components/icons/At.tsx";
import { Key } from "../components/icons/Key.tsx";
import { Code } from "../components/icons/Code.tsx";
import { Filter } from "../components/icons/Filter.tsx";
import { File } from "../components/icons/File.tsx";
import { Clock } from "../components/icons/Clock.tsx";
import { Radio } from "../components/icons/Radio.tsx";
import { Webhook } from "../components/icons/Webhook.tsx";
import { ExternalLink } from "../components/ExternalLink.tsx";
import { Filter } from "../components/icons/Filter.tsx";
import { Repeat } from "../components/icons/Repeat.tsx";
import { Webhook } from "../components/icons/Webhook.tsx";
import { FileText } from "../components/icons/FileText.tsx";
import { At } from "../components/icons/At.tsx";
import { Key } from "../components/icons/Key.tsx";
import { ExternalLink } from "../components/ExternalLink.tsx";

const sections = [
{
Expand All @@ -24,6 +25,18 @@ const sections = [
},
],
},
{
name: "Unlisted",
description: "Tools that don’t fit in a specific section yet.",
tools: [
{
href: "/creation-date",
icon: <Clock />,
name: "Creation Date",
description: "Get approximate creation date of Telegram users.",
},
],
},
{
name: "Bot API",
description: (
Expand Down

0 comments on commit 3808568

Please sign in to comment.