Skip to content

Commit

Permalink
column mapping, remote config, settings page updates
Browse files Browse the repository at this point in the history
  • Loading branch information
bjesus committed Oct 6, 2024
1 parent a5dc2bd commit 77e4021
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 44 deletions.
75 changes: 50 additions & 25 deletions app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ footer {

<script setup>
import sanitize from "sanitize-filename";
import appConfig from "./teatime.config.ts";
const appConfig = useAppConfig();
import { createDbWorker } from "sql.js-httpvfs";
import { useLocalStorage } from "@vueuse/core";
Expand All @@ -126,36 +126,48 @@ const workerUrl = new URL(
);
const wasmUrl = new URL("sql.js-httpvfs/dist/sql-wasm.wasm", import.meta.url);
const defaultColumns = Object.fromEntries(
["title", "author", "ext", "lang"].map((x) => [x, x]),
);
const remote = useLocalStorage("remote", null);
const remoteConfig = useLocalStorage("remoteConfig", null);
const ipfsGateway = useLocalStorage("ipfsGateway", "ipfs.io");
const searchQuery = useState("searchQuery", () => "");
const isLoading = useState("isLoading", () => false);
const directLink = useState("directLink", () => "");
const results = useState("results", () => []);
const view = useState("view", () => "welcome");
const darkMode = useState("darkMode", () => false);
const bookURL = useState("bookURL", () => "");
const lastResult = useState("lastResult", () => null);
const error = useState("error", () => null);
const downloadProgress = useState("downloadProgress", () => 0);
const bookFile = ref(null);
const isDragging = ref(false);
const bookProgress = ref(0);
const title = useState("title", () => appConfig.title);
const icon = useState("icon", () => appConfig.icon);
const results = ref([]);
const lastResult = ref(null);
const error = ref(null);
const downloadProgress = ref(0);
const bookFile = ref(null);
const isDragging = ref(false);
const bookProgress = ref(0);
const booksList = computed(() => {
return view.value === "history"
? JSON.parse(localStorage.getItem("history") || "[]")
: results;
});
const setResults = (books) => {
const { images } = JSON.parse(remoteConfig.value);
const { images, columns } = JSON.parse(remoteConfig.value);
results.value = books.map((b) => {
b.Coverurl = images.replace("${ipfs_cid}", b.ipfs_cid);
for (const key of Object.keys(columns)) {
b[key] = b[columns[key]];
delete b[columns[key]];
}
b.image_url = images
.replaceAll("${id}", b.id)
.replaceAll("${md5}", b.md5)
.replaceAll("${ipfs_cid}", b.ipfs_cid)
.replaceAll("${id_group}", Math.floor(b.id / 1000) * 1000);
return b;
});
};
Expand Down Expand Up @@ -200,13 +212,19 @@ const fetchResults = async (query) => {
let maxBytesToRead = 10 * 1024 * 1024;
const {
dbConfig,
tableName = "updated_data",
columns = defaultColumns,
} = JSON.parse(remoteConfig.value);
try {
console.log("Connecting to the database...");
const worker = await createDbWorker(
[
{
from: "inline",
config: JSON.parse(remoteConfig.value).dbConfig,
config: dbConfig,
},
],
workerUrl.toString(),
Expand All @@ -217,29 +235,31 @@ const fetchResults = async (query) => {
console.log("Making the query...");
if (query.length > 3) {
dbResult = await worker.db.exec(
`SELECT * FROM updated_data
`SELECT * FROM ${tableName}
WHERE id IN (
SELECT rowid FROM updated_data_fts
WHERE updated_data_fts MATCH ? )
SELECT rowid FROM ${tableName}_fts
WHERE ${tableName}_fts MATCH ? )
LIMIT 10;`,
[`Title:${query}* OR Author:${query}*`],
[`${columns.title}:${query}* OR ${columns.author}:${query}*`],
);
} else {
const params = [];
if (query.title && query.author)
params.push(`Title:${query.title} AND Author:${query.author}`);
else if (query.author) params.push(`Author:${query.author}`);
else params.push(`Title:${query.title}`); // we must have either title or author
params.push(
`${columns.title}:${query.title} AND ${columns.author}:${query.author}`,
);
else if (query.author) params.push(`${columns.author}:${query.author}`);
else params.push(`${columns.title}:${query.title}`); // we must have either title or author
if (query.lang) params.push(query.lang);
if (query.ext) params.push(query.ext);
dbResult = await worker.db.exec(
`
SELECT updated_data.* FROM updated_data
JOIN updated_data_fts ON updated_data.id = updated_data_fts.rowid
WHERE updated_data_fts MATCH ?
${query.lang ? " AND Language = ? " : ""}
${query.ext ? " AND Extension = ? " : ""}
SELECT ${tableName}.* FROM ${tableName}
JOIN ${tableName}_fts ON ${tableName}.id = ${tableName}_fts.rowid
WHERE ${tableName}_fts MATCH ?
${query.lang ? ` AND ${columns.lang} = ? ` : ""}
${query.ext ? ` AND ${columns.ext} = ? ` : ""}
LIMIT 10;`,
params,
);
Expand All @@ -261,6 +281,11 @@ const fetchResults = async (query) => {
}
};
const getBookURL = (result, filename) =>
appConfig.ipfsGateways[ipfsGateway.value].url
.replaceAll("${cid}", result.ipfs_cid)
.replaceAll("${filename}", filename);
const handleClick = async (result) => {
lastResult.value = result;
view.value = "book";
Expand All @@ -279,8 +304,8 @@ const handleClick = async (result) => {
`${result.Author} - ${result.Title}.${result.Extension}`,
);
directLink.value = appConfig.getDirectLink(result, filename);
bookURL.value = appConfig.getBookURL(result, filename);
directLink.value = false;
bookURL.value = getBookURL(result, filename);
try {
const response = await fetch(bookURL.value);
Expand Down
16 changes: 7 additions & 9 deletions components/BooksList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,20 @@
@click="onBookClick(result)"
>
<img
v-if="result.Coverurl"
:src="result.Coverurl"
v-if="result.image_url"
:src="result.image_url"
referrerpolicy="no-referrer"
/>
<div>
<h2 :title="result.Title">{{ result.Title }}</h2>
<h3>{{ result.Author }}, {{ result.Year }}</h3>
<h2 :title="result.title">{{ result.title }}</h2>
<h3>{{ result.author }}, {{ result.year }}</h3>
<span class="ext"><LucideFile :size="12" /> {{ result.ext }}</span>
<span class="ext"
><LucideFile :size="12" /> {{ result.Extension }}</span
>
<span class="ext"
><LucideLanguages :size="12" />{{ result.Language }}</span
><LucideLanguages :size="12" />{{ result.lang }}</span
>
<span class="ext"
><LucideArrowBigDownDash :size="12" />
{{ prettyBytes(result.Filesize) }}</span
{{ prettyBytes(result.size) }}</span
>
<meter min="0" max="1" :value="result.fraction" />
</div>
Expand Down
63 changes: 53 additions & 10 deletions components/Settings.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
<template>
<div id="settings">
<h2>Database</h2>
<p>Please choose a TeaTime compatible database to search in.</p>
<p :class="{ info: !remote }">
Please choose a database for TeaTime to search in
</p>
<table>
<thead>
<tr>
<th class="center">Active</th>
<th class="center">⭐</th>
<th>Name</th>
<th>Description</th>
<th>Updated</th>
<td></td>
</tr>
</thead>
<tbody>
<tr
v-for="item in remotes"
v-for="item in remotesList"
:class="{ active: item.full_name === remote }"
@click="setRemote(item)"
>
Expand All @@ -35,6 +38,9 @@
<td>
{{ item.description }}
</td>
<td>
{{ item.updated_at.slice(0, 10) }}
</td>
<td class="right">
<a :href="'https://github.com/' + item.full_name" target="_blank">
<LucideExternalLink />
Expand All @@ -43,6 +49,12 @@
</tr>
</tbody>
</table>
<button
v-if="remotes.length > 5 && !showAllRemotes"
@click="showAllRemotes = true"
>
Show all
</button>
<h2>IPFS Gateway</h2>
<p>Please choose a TeaTime compatible database to search in.</p>
<table>
Expand All @@ -56,16 +68,16 @@
</thead>
<tbody>
<tr
:class="{ active: ipfsGateway === gateway.value }"
@click="setGateway(gateway.value)"
v-for="gateway in appConfig.ipfsGateways"
v-for="(gateway, value) of appConfig.ipfsGateways"
@click="setGateway(value)"
:class="{ active: ipfsGateway === value }"
>
<td class="center">
<input
type="radio"
name="ipfsGateway"
:checked="ipfsGateway === gateway.value"
@click="setGateway(item)"
:checked="ipfsGateway === value"
@click="setGateway(value)"
/>
</td>
<td>{{ gateway.name }}</td>
Expand All @@ -89,6 +101,11 @@
table {
width: 100%;
border: 0;
tr {
cursor: pointer;
}
th {
text-align: left;
Expand All @@ -108,25 +125,53 @@
td {
margin: 0.5rem 0;
padding: 0.5rem;
vertical-align: top;
}
tr.active {
box-shadow: 0px 0px 2px 2px #ccc;
box-shadow: 0px 0px 1px 1px rgba(0, 255, 0, 0.3);
border-radius: 1rem;
background-color: rgba(0, 255, 0, 0.05);
}
}
table:has(tr:hover) tr:not(:hover) td {
color: gray;
}
p.info {
color: darkred;
background-color: rgba(255, 0, 0, 0.05);
padding: 1rem;
border: 1px solid red;
border-radius: 1rem;
&::before {
content: "ℹ️ ";
}
}
button {
display: block;
margin: 1rem auto 2rem;
}
}
</style>

<script setup>
import { useLocalStorage } from "@vueuse/core";
const appConfig = useAppConfig();
const showAllRemotes = ref(false);
const remotes = ref([]);
const remote = useLocalStorage("remote");
const remoteConfig = useLocalStorage("remoteConfig");
const ipfsGateway = useLocalStorage("ipfsGateway");
const remotesList = computed(() => {
return showAllRemotes.value ? remotes.value : remotes.value.slice(0, 5);
});
const updateRemotes = async () => {
const response = await fetch(
"https://api.github.com/search/repositories?q=topic:teatime-database&sort=stars&order=desc",
Expand All @@ -141,15 +186,13 @@ onMounted(async () => {
});
const setRemote = async (selection) => {
console.log(selection.full_name);
const [owner, repo] = selection.full_name.split("/");
const response = await fetch(
`https://${owner}.github.io/${repo}/config.json`,
);
const config = await response.json();
remoteConfig.value = JSON.stringify(config);
remote.value = selection.full_name;
console.log(config);
};
const setGateway = async (gateway) => {
Expand Down

0 comments on commit 77e4021

Please sign in to comment.