diff --git a/.env.example b/.env.example index c134133..9d7fb34 100644 --- a/.env.example +++ b/.env.example @@ -5,4 +5,16 @@ VITE_API=http://localhost:3001 TMDB_API_KEY="..." TVDB_API_KEY="..." VIDEO_THUMBNAIL_TIME=10 -FANART_TV_API_KEY=".." \ No newline at end of file +FANART_TV_API_KEY=".." + +# MongoDB +MONGO_HOST=mongo +MONGO_PORT=27017 +MONGO_DB=dupe +MONGO_AUTH_SOURCE=admin +MONGO_INITDB_ROOT_USERNAME=dupe +MONGO_INITDB_ROOT_PASSWORD=dupe +MONGO_USER=dupe +MONGO_PASS=dupe +# Opsiyonel özel bağlantı stringi (MONGO_HOST/PORT yerine geçer) +# MONGO_URI=mongodb://dupe:dupe@mongo:27017/dupe?authSource=admin diff --git a/.gitignore b/.gitignore index db69546..3f42121 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Node modules */node_modules/ jspm_packages/ +/data # Logs npm-debug.log* diff --git a/docker-compose.yml b/docker-compose.yml index d0a7aa6..8106b49 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,25 @@ version: "3.9" services: + mongo: + image: mongo:7 + container_name: mongo + restart: unless-stopped + environment: + MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME:-dupe} + MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD:-dupe} + MONGO_INITDB_DATABASE: ${MONGO_DB:-dupe} + volumes: + - ./data/mongo:/data/db + - ./mongo-init:/docker-entrypoint-initdb.d:ro + ports: + - "27017:27017" + dupe: build: . container_name: app + depends_on: + - mongo ports: - "3001:3001" volumes: @@ -18,3 +34,9 @@ services: TVDB_API_KEY: ${TVDB_API_KEY} FANART_TV_API_KEY: ${FANART_TV_API_KEY} VIDEO_THUMBNAIL_TIME: ${VIDEO_THUMBNAIL_TIME} + MONGO_HOST: ${MONGO_HOST:-mongo} + MONGO_PORT: ${MONGO_PORT:-27017} + MONGO_DB: ${MONGO_DB:-dupe} + MONGO_USER: ${MONGO_INITDB_ROOT_USERNAME:-dupe} + MONGO_PASS: ${MONGO_INITDB_ROOT_PASSWORD:-dupe} + MONGO_AUTH_SOURCE: ${MONGO_AUTH_SOURCE:-admin} diff --git a/mongo-init/init.js b/mongo-init/init.js new file mode 100644 index 0000000..998ef0a --- /dev/null +++ b/mongo-init/init.js @@ -0,0 +1,24 @@ +// MongoDB başlangıç scripti: istenen veritabanını açar ve boş bir koleksiyonla başlatır +(async () => { + const dbName = + process.env.MONGO_DB || + process.env.MONGO_INITDB_DATABASE || + "dupe"; + + // Mevcut bağlantı, root kullanıcı ile admin DB üzerinden geliyor + const db = db.getSiblingDB(dbName); + + const marker = "dupe_init_marker"; + const collections = await db.getCollectionNames(); + + if (!collections.includes(marker)) { + db.createCollection(marker); + db[marker].insertOne({ + createdAt: new Date(), + note: "dupe init marker" + }); + print(`📦 '${dbName}' veritabanı için init marker oluşturuldu.`); + } else { + print(`ℹ️ '${dbName}' veritabanı zaten başlatılmış.`); + } +})(); diff --git a/server/modules/db.js b/server/modules/db.js new file mode 100644 index 0000000..a9af71e --- /dev/null +++ b/server/modules/db.js @@ -0,0 +1,39 @@ +import { MongoClient } from "mongodb"; + +const MONGO_HOST = process.env.MONGO_HOST || "mongo"; +const MONGO_PORT = process.env.MONGO_PORT || "27017"; +const MONGO_DB = process.env.MONGO_DB || "dupe"; +const MONGO_USER = process.env.MONGO_USER || "dupe"; +const MONGO_PASS = process.env.MONGO_PASS || "dupe"; +const MONGO_AUTH_SOURCE = process.env.MONGO_AUTH_SOURCE || "admin"; + +const DEFAULT_URI = `mongodb://${encodeURIComponent(MONGO_USER)}:${encodeURIComponent( + MONGO_PASS +)}@${MONGO_HOST}:${MONGO_PORT}/${encodeURIComponent(MONGO_DB)}?authSource=${encodeURIComponent( + MONGO_AUTH_SOURCE +)}`; + +const MONGO_URI = process.env.MONGO_URI || DEFAULT_URI; + +let client = null; +let db = null; + +export async function connectMongo() { + if (client && db) return { client, db }; + + const mongoClient = new MongoClient(MONGO_URI, { + maxPoolSize: 10, + serverSelectionTimeoutMS: 5000 + }); + + await mongoClient.connect(); + client = mongoClient; + db = mongoClient.db(MONGO_DB); + + console.log(`📦 MongoDB bağlantısı hazır (db: ${db.databaseName})`); + return { client, db }; +} + +export function getDb() { + return db; +} diff --git a/server/package.json b/server/package.json index 7b966be..c220dc2 100644 --- a/server/package.json +++ b/server/package.json @@ -8,6 +8,7 @@ "dependencies": { "cors": "^2.8.5", "express": "^4.19.2", + "mongodb": "^6.9.0", "jsonwebtoken": "^9.0.2", "mime-types": "^2.1.35", "multer": "^1.4.5-lts.1", diff --git a/server/server.js b/server/server.js index 2da7f94..5b2c27d 100644 --- a/server/server.js +++ b/server/server.js @@ -13,6 +13,7 @@ import { createAuth } from "./modules/auth.js"; import { buildHealthReport, healthRouter } from "./modules/health.js"; import { restoreTorrentsFromDisk } from "./modules/state.js"; import { createWebsocketServer, broadcastJson } from "./modules/websocket.js"; +import { connectMongo, getDb } from "./modules/db.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -97,6 +98,16 @@ app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use("/downloads", express.static(DOWNLOAD_DIR)); +// MongoDB bağlantısını başlat +connectMongo() + .then(({ db }) => { + app.locals.db = db; + app.locals.getDb = getDb; + }) + .catch((err) => { + console.error("❌ MongoDB bağlantısı kurulamadı:", err.message); + }); + // --- En uygun video dosyasını seç --- function pickBestVideoFile(torrent) { const videos = torrent.files