Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
# Production Dockerfile for OpenTracker
FROM node:20-alpine AS base

ARG TRACKER_HTTP_URL
ARG TRACKER_UDP_URL
ARG TRACKER_WS_URL

ENV TRACKER_HTTP_URL=${TRACKER_HTTP_URL}
ENV TRACKER_UDP_URL=${TRACKER_UDP_URL}
ENV TRACKER_WS_URL=${TRACKER_WS_URL}


# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat
Expand Down
18 changes: 17 additions & 1 deletion app/components/TorrentTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
v-if="torrent.category"
class="text-[10px] bg-bg-tertiary border border-border px-1.5 py-0.5 rounded-sm text-text-secondary uppercase font-bold tracking-wider"
>
{{ torrent.category.name }}
{{ getCategoryDisplayName(torrent.category) }}
</span>
<span v-else class="text-xs text-text-muted">—</span>
</td>
Expand Down Expand Up @@ -128,6 +128,8 @@ interface TorrentWithStats {
};
}

const { data: categories } = await useFetch('/api/categories');

const props = defineProps<{
torrents: TorrentWithStats[];
compact?: boolean;
Expand All @@ -138,6 +140,20 @@ const emit = defineEmits<{
deleted: [infoHash: string];
}>();

function getCategoryDisplayName(category) {
let displayName = category.name;

const parent = categories.value.find(
(cat) => cat.id === category.parentId
);

if (parent) {
displayName = `${parent.name}/${displayName}`;
}

return displayName;
}

async function deleteTorrent(torrent: TorrentWithStats) {
if (!confirm(`Delete "${torrent.name}"?`)) return;

Expand Down
22 changes: 21 additions & 1 deletion app/components/UploadTorrentModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
class="input w-full !py-2 text-xs font-bold uppercase tracking-wider"
>
<option value="">Select a category...</option>
<option v-for="cat in categories" :key="cat.id" :value="cat.id">
<option v-for="cat in getFlattenedCategories(categories)" :key="cat.id" :value="cat.id">
{{ cat.name }}
</option>
</select>
Expand Down Expand Up @@ -344,6 +344,26 @@ const renderedDescription = computed(() => {
return marked.parse(description.value || '');
});

function getFlattenedCategories(
categories: Array<{ id: string; name: string; subcategories?: any[] }>,
prefix = ''
): Array<{ id: string; name: string }> {

let result: Array<{ id: string; name: string }> = [];

for (const category of categories) {
result.push({ id: category.id, name: prefix + category.name });

if (category.subcategories) {
result = result.concat(
getFlattenedCategories(category.subcategories, prefix + '╚=> ')
);
}
}

return result;
}

function close() {
emit('close');
// Reset state after animation
Expand Down
2 changes: 1 addition & 1 deletion app/pages/search.vue
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ const {
}>('/api/torrents', {
query: computed(() => ({
search: searchQuery.value,
category: selectedCategory.value,
categoryId: selectedCategory.value,
page: page.value,
limit: 20,
})),
Expand Down
6 changes: 3 additions & 3 deletions app/pages/torrents/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ const router = useRouter();

const search = ref((route.query.search as string) || '');
const page = ref(parseInt((route.query.page as string) || '1', 10));
const selectedCategory = ref((route.query.category as string) || '');
const selectedCategory = ref((route.query.categoryId as string) || '');

const showUploadModal = ref(false);

Expand All @@ -160,7 +160,7 @@ const { data, refresh, pending } = await useFetch<{
page: page.value,
limit: 25,
search: search.value || undefined,
category: selectedCategory.value || undefined,
categoryId: selectedCategory.value || undefined,
})),
});

Expand All @@ -178,7 +178,7 @@ function doSearch() {
router.push({
query: {
search: search.value || undefined,
category: selectedCategory.value || undefined,
categoryId: selectedCategory.value || undefined,
page: undefined,
},
});
Expand Down
4 changes: 4 additions & 0 deletions docker-compose.loadtest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ services:
build:
context: .
dockerfile: Dockerfile
args:
TRACKER_HTTP_URL: ${TRACKER_HTTP_URL:-http://localhost:8080/announce}
TRACKER_UDP_URL: ${TRACKER_UDP_URL:-udp://localhost:8081/announce}
TRACKER_WS_URL: ${TRACKER_WS_URL:-ws://localhost:8082}
container_name: trackarr-loadtest
restart: unless-stopped
environment:
Expand Down
4 changes: 4 additions & 0 deletions docker-compose.local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ services:
build:
context: .
dockerfile: Dockerfile
args:
TRACKER_HTTP_URL: ${TRACKER_HTTP_URL:-http://localhost:8080/announce}
TRACKER_UDP_URL: ${TRACKER_UDP_URL:-udp://localhost:8081/announce}
TRACKER_WS_URL: ${TRACKER_WS_URL:-ws://localhost:8082}
container_name: trackarr
restart: unless-stopped
environment:
Expand Down
4 changes: 4 additions & 0 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ services:
build:
context: .
dockerfile: Dockerfile
args:
TRACKER_HTTP_URL: ${TRACKER_HTTP_URL:-http://localhost:8080/announce}
TRACKER_UDP_URL: ${TRACKER_UDP_URL:-udp://localhost:8081/announce}
TRACKER_WS_URL: ${TRACKER_WS_URL:-ws://localhost:8082}
container_name: trackarr-app
restart: always
# Enhanced security: Drop all capabilities and add only required ones
Expand Down
4 changes: 4 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ services:
build:
context: .
target: base
args:
TRACKER_HTTP_URL: ${TRACKER_HTTP_URL:-http://localhost:8080/announce}
TRACKER_UDP_URL: ${TRACKER_UDP_URL:-udp://localhost:8081/announce}
TRACKER_WS_URL: ${TRACKER_WS_URL:-ws://localhost:8082}
container_name: trackarr-app
restart: unless-stopped
ports:
Expand Down
12 changes: 11 additions & 1 deletion server/api/torrents/index.get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,17 @@ export default defineEventHandler(async (event) => {
}
}
if (query.categoryId) {
conditions.push(eq(schema.torrents.categoryId, query.categoryId));
// add category and subcategories filter
const subcategories = await db.query.categories.findMany({
where: eq(schema.categories.parentId, query.categoryId),
select: { id: true },
});
conditions.push(
or(
eq(schema.torrents.categoryId, query.categoryId),
...subcategories.map((subcat) => eq(schema.torrents.categoryId, subcat.id))
)
);
}

const whereClause = conditions.length > 0 ? and(...conditions) : undefined;
Expand Down