Initial commit

This commit is contained in:
Yas Opisso
2025-12-12 14:56:50 -05:00
commit ebd684dc53
20 changed files with 24382 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

8
.env Normal file
View File

@@ -0,0 +1,8 @@
# DATABASE
POCKETBASE_PORT=9090
POCKETBASE_ADMIN_USERNAME="me@yasopisso.com"
POCKETBASE_ADMIN_PASSWORD="manager12"
#MOVIEDB
API_KEY="9311701ee4cc5d2a470e41e8be09f6d5"
API_READ_ACCESS_TOKEN="eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI5MzExNzAxZWU0Y2M1ZDJhNDcwZTQxZThiZTA5ZjZkNSIsIm5iZiI6MTc2NTQyNzY4MS43Mjg5OTk5LCJzdWIiOiI2OTNhNDllMWZhYTJlNmE1MmMxZmYxZjQiLCJzY29wZXMiOlsiYXBpX3JlYWQiXSwidmVyc2lvbiI6MX0._bxR8N28w_ARtwiGF1fkbCrJ5NNG3SSv6r0BfcwG2lo"

72
.gitginore Normal file
View File

@@ -0,0 +1,72 @@
# ==========================
# macOS System Files
# ==========================
.DS_Store
.AppleDouble
.LSOverride
._*
# ==========================
# Python (FastAPI)
# ==========================
__pycache__/
*.py[cod]
*$py.class
# Virtual Environments
venv/
.venv/
env/
.env/
# Distribution / Packaging
dist/
build/
*.egg-info/
# Unit Test / Coverage
.pytest_cache/
.coverage
htmlcov/
# Type Checking
.mypy_cache/
# ==========================
# Node.js & Svelte
# ==========================
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# SvelteKit specific
.svelte-kit/
build/
.vercel/
.netlify/
# ==========================
# PocketBase (Assuming typo)
# ==========================
# Stores the actual database and user uploaded files
# You usually want to keep 'pb_migrations' but ignore the data
pb_data/
pb_public/
# ==========================
# Environment Variables (CRITICAL)
# ==========================
# Never commit secrets or API keys
.env
.env.local
.env.*.local
# ==========================
# IDE / Editor Settings
# ==========================
.vscode/
.idea/
*.swp
*.swo

88
_scratch/moviedb.py Normal file
View File

@@ -0,0 +1,88 @@
import requests
# API Key provided by the user
API_KEY = "9311701ee4cc5d2a470e41e8be09f6d5"
POCKETBASE_URL = "http://localhost:9090"
COLLECTION_NAME = "genres"
def get_movie_genres():
"""
Fetches all available movie genres from TMDB API using requests.
Returns:
list: A list of dictionaries representing genres.
"""
url = f"https://api.themoviedb.org/3/genre/movie/list?api_key={API_KEY}&language=en-US"
try:
response = requests.get(url)
response.raise_for_status()
data = response.json()
return data.get("genres", [])
except requests.exceptions.RequestException as e:
print(f"Error fetching genres: {e}")
return []
def save_genres_to_pocketbase(genres):
"""
Stores genres in the PocketBase 'genres' collection.
Checks if a genre with the same name already exists before creating it.
Args:
genres (list): A list of dictionaries with 'id' and 'name'.
"""
base_url = f"{POCKETBASE_URL}/api/collections/{COLLECTION_NAME}/records"
print(f"Processing {len(genres)} genres for PocketBase at {base_url}...")
for genre in genres:
genre_name = genre["name"]
# Check if genre already exists
try:
# PocketBase filter syntax: name='GenreName'
# We use params to let requests handle URL encoding properly
check_response = requests.get(
base_url, params={"filter": f"name='{genre_name}'"}
)
check_response.raise_for_status()
existing_data = check_response.json()
# PocketBase list response structure has 'items' and 'totalItems'
if existing_data.get("totalItems", 0) > 0:
print(f"Skipped (already exists): {genre_name}")
continue
except requests.exceptions.RequestException as e:
print(f"Error checking existence for {genre_name}: {e}")
continue
# Create new record if it doesn't exist
payload = {"name": genre_name}
try:
response = requests.post(base_url, json=payload)
if response.status_code == 200:
print(f"Saved: {genre_name}")
else:
# Log failure details
print(
f"Failed to save {genre_name}: {response.status_code} - {response.text}"
)
except requests.exceptions.RequestException as e:
print(f"Error saving {genre_name}: {e}")
if __name__ == "__main__":
genres = get_movie_genres()
if genres:
print(f"Found {len(genres)} genres:")
for genre in genres:
print(f"ID: {genre['id']}, Name: {genre['name']}")
print("-" * 30)
save_genres_to_pocketbase(genres)
else:
print("No genres found or an error occurred.")

25
docker-compose.yml Normal file
View File

@@ -0,0 +1,25 @@
services:
viewarr-database:
build:
context: ./pocketbase
dockerfile: Dockerfile
container_name: viewarr-database
restart: unless-stopped
environment:
- POCKETBASE_ADMIN_USERNAME=${POCKETBASE_ADMIN_USERNAME}
- POCKETBASE_ADMIN_PASSWORD=${POCKETBASE_ADMIN_PASSWORD}
ports:
- "${POCKETBASE_PORT}:8090"
volumes:
- ./pocketbase/pb_data:/home/pocketbase/pb_data
- ./pocketbase/pb_public:/home/pocketbase/pb_public
- ./pocketbase/pb_hooks:/home/pocketbase/pb_hooks
- ./pocketbase/pb_migrations:/home/pocketbase/pb_migrations
networks:
- viewarr-network
networks:
viewarr-network:
name: viewarr-network
driver: bridge
# docker compose up -d --force-recreate --build

Binary file not shown.

15
fastapi/main.py Normal file
View File

@@ -0,0 +1,15 @@
from typing import Union
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}

40
fastapi/requirements.txt Normal file
View File

@@ -0,0 +1,40 @@
annotated-doc==0.0.4
annotated-types==0.7.0
anyio==4.12.0
certifi==2025.11.12
click==8.3.1
dnspython==2.8.0
email-validator==2.3.0
fastapi==0.124.2
fastapi-cli==0.0.16
fastapi-cloud-cli==0.6.0
fastar==0.8.0
h11==0.16.0
httpcore==1.0.9
httptools==0.7.1
httpx==0.28.1
idna==3.11
Jinja2==3.1.6
markdown-it-py==4.0.0
MarkupSafe==3.0.3
mdurl==0.1.2
pydantic==2.12.5
pydantic_core==2.41.5
Pygments==2.19.2
python-dotenv==1.2.1
python-multipart==0.0.20
PyYAML==6.0.3
rich==14.2.0
rich-toolkit==0.17.0
rignore==0.7.6
sentry-sdk==2.47.0
shellingham==1.5.4
starlette==0.50.0
typer==0.20.0
typing-inspection==0.4.2
typing_extensions==4.15.0
urllib3==2.6.1
uvicorn==0.38.0
uvloop==0.22.1
watchfiles==1.1.1
websockets==15.0.1

BIN
pocketbase/.DS_Store vendored Normal file

Binary file not shown.

23
pocketbase/Dockerfile Executable file
View File

@@ -0,0 +1,23 @@
FROM alpine:latest
ARG PB_VERSION=0.34.2
RUN apk --no-cache add curl
RUN adduser -s /bin/bash -D pocketbase
USER pocketbase
WORKDIR /home/pocketbase
RUN curl -LJ "https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_amd64.zip" -o pb.zip
RUN unzip pb
RUN rm pb.zip
RUN mkdir pb_data
RUN mkdir pb_hooks
RUN mkdir pb_migrations
RUN mkdir pb_public
EXPOSE 8090
COPY --chown=pocketbase --chmod=700 ./pb_data/ ./pb_hooks/ ./pb_migrations/ ./pb_public/
COPY --chown=pocketbase --chmod=700 ./initialize.sh .
ENTRYPOINT [ "./initialize.sh" ]

22
pocketbase/initialize.sh Executable file
View File

@@ -0,0 +1,22 @@
#!/bin/sh
echo "Starting PocketBase initialization..."
DB_FILE="./pb_data/data.db"
# Step 1: Ensure the database file exists
if [ ! -f "$DB_FILE" ]; then
# echo "Database not found. Copying default data..."
# cp -r ./pb_data_default/. ./pb_data/
# This is only needed if we don't copy the default data
./pocketbase serve --http 0.0.0.0:8090 --automigrate=0 & sleep 4
kill $(pidof pocketbase)
# Creates the admin user or updates if already exists
echo "Creating admin user"
./pocketbase superuser upsert "$POCKETBASE_ADMIN_USERNAME" "$POCKETBASE_ADMIN_PASSWORD"
fi
# Step 3: Start PocketBase normally
echo "Starting PocketBase..."
./pocketbase serve --http 0.0.0.0:8090

Binary file not shown.

BIN
pocketbase/pb_data/data.db Normal file

Binary file not shown.

23849
pocketbase/pb_data/types.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

BIN
pocketbase/pb_migrations/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,113 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"fields": [
{
"autogeneratePattern": "[a-z0-9]{15}",
"hidden": false,
"id": "text3208210256",
"max": 15,
"min": 15,
"name": "id",
"pattern": "^[a-z0-9]+$",
"presentable": false,
"primaryKey": true,
"required": true,
"system": true,
"type": "text"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "text724990059",
"max": 0,
"min": 0,
"name": "title",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "text3145888567",
"max": 0,
"min": 0,
"name": "year",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "text762383602",
"max": 0,
"min": 0,
"name": "poster",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "text3458754147",
"max": 0,
"min": 0,
"name": "summary",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"hidden": false,
"id": "autodate2990389176",
"name": "created",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
},
{
"hidden": false,
"id": "autodate3332085495",
"name": "updated",
"onCreate": true,
"onUpdate": true,
"presentable": false,
"system": false,
"type": "autodate"
}
],
"id": "pbc_2708086759",
"indexes": [],
"listRule": null,
"name": "media",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_2708086759");
return app.delete(collection);
})

View File

@@ -0,0 +1,71 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"fields": [
{
"autogeneratePattern": "[a-z0-9]{15}",
"hidden": false,
"id": "text3208210256",
"max": 15,
"min": 15,
"name": "id",
"pattern": "^[a-z0-9]+$",
"presentable": false,
"primaryKey": true,
"required": true,
"system": true,
"type": "text"
},
{
"autogeneratePattern": "",
"hidden": false,
"id": "text1579384326",
"max": 0,
"min": 0,
"name": "name",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": false,
"system": false,
"type": "text"
},
{
"hidden": false,
"id": "autodate2990389176",
"name": "created",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": false,
"type": "autodate"
},
{
"hidden": false,
"id": "autodate3332085495",
"name": "updated",
"onCreate": true,
"onUpdate": true,
"presentable": false,
"system": false,
"type": "autodate"
}
],
"id": "pbc_2683869272",
"indexes": [],
"listRule": null,
"name": "genres",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_2683869272");
return app.delete(collection);
})

View File

@@ -0,0 +1,28 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_2683869272")
// update collection data
unmarshal({
"createRule": "",
"deleteRule": "",
"listRule": "",
"updateRule": "",
"viewRule": ""
}, collection)
return app.save(collection)
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_2683869272")
// update collection data
unmarshal({
"createRule": null,
"deleteRule": null,
"listRule": null,
"updateRule": null,
"viewRule": null
}, collection)
return app.save(collection)
})

View File

@@ -0,0 +1,28 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_2708086759")
// add field
collection.fields.addAt(5, new Field({
"cascadeDelete": false,
"collectionId": "pbc_2683869272",
"hidden": false,
"id": "relation2834031894",
"maxSelect": 999,
"minSelect": 0,
"name": "genres",
"presentable": false,
"required": false,
"system": false,
"type": "relation"
}))
return app.save(collection)
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_2708086759")
// remove field
collection.fields.removeById("relation2834031894")
return app.save(collection)
})

BIN
pocketbase/pb_public/.DS_Store vendored Normal file

Binary file not shown.