Add updated Goondex logos

This commit is contained in:
Stu Leak 2025-12-04 10:49:46 -05:00
parent 99d72c4758
commit e3d253ba92
22 changed files with 2430 additions and 236 deletions

50
.air.toml Normal file
View File

@ -0,0 +1,50 @@
# Air configuration for Goondex live reload
# See: https://github.com/air-verse/air
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"
[build]
args_bin = []
bin = "./tmp/goondex"
cmd = "go build -o ./tmp/goondex ./cmd/goondex"
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata", "docs", ".git", "node_modules"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
# Watch all web-related files for changes
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html", "css", "js"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = []
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false
[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"
[log]
main_only = false
time = true
[misc]
clean_on_exit = false
[screen]
clear_on_rebuild = false
keep_scroll = true

6
.gitignore vendored
View File

@ -21,6 +21,12 @@
/cache/
/tmp/
# Node modules (Bootstrap)
node_modules/
# Air live reload
build-errors.log
# Media & Assets (images, galleries, downloads)
# Ignore all assets except logos and README
/assets/*

64
Makefile Normal file
View File

@ -0,0 +1,64 @@
.PHONY: help dev build run clean install-deps install-air test
# Default target
help:
@echo "Goondex Development Commands:"
@echo ""
@echo " make dev - Start development server with live reload (Air)"
@echo " make build - Build production binary"
@echo " make run - Run production binary"
@echo " make clean - Clean build artifacts"
@echo " make install-deps - Install all dependencies"
@echo " make install-air - Install Air for live reload"
@echo " make test - Run tests"
@echo ""
# Development with Air (live reload)
dev: install-air
air
# Build production binary
build:
@echo "Building Goondex..."
@mkdir -p bin
go build -o ./bin/goondex ./cmd/goondex
@echo "Built: ./bin/goondex"
# Run production build
run: build
./bin/goondex serve
# Clean build artifacts
clean:
@echo "Cleaning build artifacts..."
rm -rf tmp/
rm -rf bin/
rm -f build-errors.log
@echo "Cleaned!"
# Install all dependencies
install-deps: install-air
@echo "All dependencies installed!"
# Install Air for live reload
install-air:
@if ! command -v air >/dev/null 2>&1; then \
echo "Installing Air..."; \
go install github.com/air-verse/air@latest; \
echo "Air installed! Make sure ~/go/bin is in your PATH"; \
else \
echo "Air is already installed"; \
fi
# Run tests
test:
go test -v ./...
# Database migrations (if needed in future)
migrate-up:
@echo "Running migrations..."
# Add migration commands here
migrate-down:
@echo "Rolling back migrations..."
# Add rollback commands here

View File

@ -8,6 +8,8 @@ Goondex ingests metadata from external sources (ThePornDB, etc.), normalizes it,
**v0.1.0-dev2** - TPDB Integration Release
> Note: TPDB import/sync commands are temporarily disabled. Use the Adult Empire commands (`goondex adultemp ...`) to build your directory for now.
## Features (v0.1.0-dev2)
- ✅ SQLite database with WAL mode for performers, studios, scenes, and tags
@ -160,6 +162,13 @@ go build -o bin/goondex ./cmd/goondex
go run ./cmd/goondex performer-search "test"
```
### Scripts
- `source scripts/env.sh` - Pin Go caches inside the repo (recommended before building)
- `scripts/build.sh` - Build the CLI (`bin/goondex`)
- `ADDR=localhost:8788 scripts/run.sh` - Build (if needed) and start the web UI
- `scripts/test.sh` - Run `go test ./cmd/... ./internal/...`
### Building & Rebuilding the CLI
The Goondex binary is not rebuilt automatically—whenever you change Go files (especially under `cmd/goondex` or `internal/*`), rebuild before re-running commands.

View File

@ -19,6 +19,7 @@ import (
)
const tpdbAPIKeyEnvVar = "TPDB_API_KEY"
const tpdbEnabled = false
var (
dbPath string
@ -48,7 +49,7 @@ func init() {
rootCmd.AddCommand(versionCmd)
performerSearchCmd.Flags().Bool("show-bio", false, "Show performer bio in search results")
performerGetCmd.Flags().Bool("show-bio", false, "Show performer bio")
webCmd.Flags().String("addr", "localhost:8080", "Address to listen on")
webCmd.Flags().String("addr", "localhost:8788", "Address to listen on")
// Sync command flags
syncCmd.PersistentFlags().Bool("force", false, "Force sync even if rate limit not met")
@ -58,8 +59,8 @@ func init() {
// Import command with subcommands
var importCmd = &cobra.Command{
Use: "import",
Short: "Import data from external sources (TPDB)",
Long: `Import performers, studios, and scenes from ThePornDB into your local database.`,
Short: "Import data (Adult Empire available; TPDB disabled)",
Long: `Adult Empire import commands are available. TPDB bulk import commands are temporarily disabled while we focus on Adult Empire data.`,
}
var importAllCmd = &cobra.Command{
@ -151,20 +152,10 @@ func init() {
// Sync command with subcommands
var syncCmd = &cobra.Command{
Use: "sync",
Short: "Sync and update existing data from TPDB",
Long: `Update existing performers, studios, and scenes with latest data from ThePornDB.
Short: "Sync and update existing data (TPDB disabled for now)",
Long: `TPDB-based sync is temporarily disabled while we prioritize Adult Empire as the main source.
Rate limiting is enforced to prevent excessive API calls:
- Default minimum interval: 1 hour
- Recommended interval: 24 hours
- Use --force to override rate limiting
Examples:
goondex sync all # Sync all entities (with 1h rate limit)
goondex sync all --interval 24h # Sync all entities (24h rate limit)
goondex sync all --force # Force sync, ignore rate limit
goondex sync performers # Sync only performers
goondex sync status # View last sync times`,
Existing sync commands are left in place for when TPDB is re-enabled, but they will currently return a disabled message.`,
}
func init() {
@ -445,6 +436,10 @@ func formatDuration(d time.Duration) string {
}
func getTPDBAPIKey() (string, error) {
if !tpdbEnabled {
return "", fmt.Errorf("TPDB integration is disabled. Use Adult Empire commands (e.g., 'goondex adultemp search-performer' and 'goondex adultemp scrape-performer <url>') to import data instead.")
}
apiKey := os.Getenv(tpdbAPIKeyEnvVar)
if apiKey == "" {
return "", fmt.Errorf("%s environment variable is not set.\n%s", tpdbAPIKeyEnvVar, apiKeySetupInstructions())
@ -499,9 +494,9 @@ var versionCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Goondex v0.1.0-dev5")
fmt.Println("Features:")
fmt.Println(" • TPDB integration with auto-import & bulk commands")
fmt.Println(" • Adult Empire scraper (scenes & performers)")
fmt.Println(" • Multi-source data merging")
fmt.Println(" • TPDB commands temporarily disabled (Adult Empire-only mode)")
fmt.Println(" • Multi-source data merging (when TPDB is re-enabled)")
fmt.Println(" • Grid-based web UI with GX components")
fmt.Println(" • Performer/studio/scene management")
},
@ -509,7 +504,7 @@ var versionCmd = &cobra.Command{
var performerSearchCmd = &cobra.Command{
Use: "performer-search [query]",
Short: "Search for performers (auto-fetches from TPDB if not in local database)",
Short: "Search for performers (imports from Adult Empire if missing locally)",
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
query := args[0]
@ -527,55 +522,60 @@ var performerSearchCmd = &cobra.Command{
return fmt.Errorf("search failed: %w", err)
}
// If no local results, try fetching from TPDB
// If no local results, pull the top Adult Empire match
if len(performers) == 0 {
fmt.Printf("No local results found. Searching TPDB for '%s'...\n", query)
fmt.Printf("No local results found. Searching Adult Empire for '%s'...\n", query)
apiKey, err := getTPDBAPIKey()
scraper, err := adultemp.NewScraper()
if err != nil {
fmt.Printf("⚠ %s\n", err)
return nil
return fmt.Errorf("failed to create Adult Empire scraper: %w", err)
}
scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)
tpdbPerformers, err := scraper.SearchPerformers(context.Background(), query)
results, err := scraper.SearchPerformersByName(context.Background(), query)
if err != nil {
fmt.Printf("⚠ TPDB search failed: %v\n", err)
fmt.Printf("⚠ Adult Empire search failed: %v\n", err)
return nil
}
if len(tpdbPerformers) == 0 {
fmt.Println("No performers found on TPDB either.")
if len(results) == 0 {
fmt.Println("No performers found on Adult Empire either.")
return nil
}
fmt.Printf("Found %d performer(s) on TPDB. Fetching full details...\n\n", len(tpdbPerformers))
fmt.Printf("Found %d performer(s) on Adult Empire. Importing the top match...\n\n", len(results))
// Import from TPDB with enriched data
imported := 0
for _, p := range tpdbPerformers {
// Fetch full details for this performer
fullPerformer, err := scraper.GetPerformerByID(context.Background(), p.SourceID)
if err != nil {
fmt.Printf("⚠ Failed to fetch details for %s: %v\n", p.Name, err)
// Fall back to search result
fullPerformer = &p
}
if err := store.Create(fullPerformer); err != nil {
fmt.Printf("⚠ Failed to import %s: %v\n", fullPerformer.Name, err)
continue
}
imported++
// Import only the top result to avoid wrong matches; use search-performer for manual selection
top := results[0]
performerData, err := scraper.ScrapePerformerByURL(context.Background(), top.URL)
if err != nil {
fmt.Printf("⚠ Failed to fetch Adult Empire details: %v\n", err)
return nil
}
// Search again to get the imported performers with their IDs
performer := scraper.ConvertPerformerToModel(performerData)
if err := store.Create(performer); err != nil {
fmt.Printf("⚠ Failed to import %s: %v\n", performer.Name, err)
} else {
fmt.Printf("✓ Imported %s from Adult Empire\n", performer.Name)
}
// Search again to get the imported performer with their ID
performers, err = store.Search(query)
if err != nil {
return fmt.Errorf("search failed after import: %w", err)
}
fmt.Printf("✓ Imported %d performer(s)\n\n", imported)
if len(performers) == 0 {
fmt.Println("No performers matched locally even after Adult Empire import.")
return nil
}
if len(results) > 1 {
fmt.Println("Tip: run 'goondex adultemp search-performer \"<name>\"' to pick a different match.")
}
imported := 1
fmt.Printf("\n✓ Imported %d performer(s)\n\n", imported)
}
fmt.Printf("Found %d performer(s):\n\n", len(performers))
@ -916,7 +916,7 @@ var performerGetCmd = &cobra.Command{
var studioSearchCmd = &cobra.Command{
Use: "studio-search [query]",
Short: "Search for studios (auto-fetches from TPDB if not in local database)",
Short: "Search for studios (local database only; TPDB disabled)",
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
query := args[0]
@ -933,49 +933,6 @@ var studioSearchCmd = &cobra.Command{
return fmt.Errorf("search failed: %w", err)
}
// If no local results, try fetching from TPDB
if len(studios) == 0 {
fmt.Printf("No local results found. Searching TPDB for '%s'...\n", query)
apiKey, err := getTPDBAPIKey()
if err != nil {
fmt.Printf("⚠ %s\n", err)
return nil
}
scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)
tpdbStudios, err := scraper.SearchStudios(context.Background(), query)
if err != nil {
fmt.Printf("⚠ TPDB search failed: %v\n", err)
return nil
}
if len(tpdbStudios) == 0 {
fmt.Println("No studios found on TPDB either.")
return nil
}
fmt.Printf("Found %d studio(s) on TPDB. Importing...\n\n", len(tpdbStudios))
// Import from TPDB
imported := 0
for _, s := range tpdbStudios {
if err := store.Create(&s); err != nil {
fmt.Printf("⚠ Failed to import %s: %v\n", s.Name, err)
continue
}
imported++
}
// Search again to get the imported studios with their IDs
studios, err = store.Search(query)
if err != nil {
return fmt.Errorf("search failed after import: %w", err)
}
fmt.Printf("✓ Imported %d studio(s)\n\n", imported)
}
fmt.Printf("Found %d studio(s):\n\n", len(studios))
for _, s := range studios {
fmt.Printf("ID: %d\n", s.ID)
@ -1079,7 +1036,7 @@ var studioGetCmd = &cobra.Command{
var sceneSearchCmd = &cobra.Command{
Use: "scene-search [query]",
Short: "Search for scenes (auto-fetches from TPDB if not in local database)",
Short: "Search for scenes (local database only; TPDB disabled)",
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
query := args[0]
@ -1096,55 +1053,6 @@ var sceneSearchCmd = &cobra.Command{
return fmt.Errorf("search failed: %w", err)
}
// If no local results, try fetching from TPDB
if len(scenes) == 0 {
fmt.Printf("No local results found. Searching TPDB for '%s'...\n", query)
apiKey, err := getTPDBAPIKey()
if err != nil {
fmt.Printf("⚠ %s\n", err)
return nil
}
scraper := tpdb.NewScraper("https://api.theporndb.net", apiKey)
tpdbScenes, err := scraper.SearchScenes(context.Background(), query)
if err != nil {
fmt.Printf("⚠ TPDB search failed: %v\n", err)
return nil
}
if len(tpdbScenes) == 0 {
fmt.Println("No scenes found on TPDB either.")
return nil
}
fmt.Printf("Found %d scene(s) on TPDB. Importing (basic metadata only)...\n\n", len(tpdbScenes))
// Import scenes (simplified - just scene metadata, no relationships)
imported := 0
for _, sc := range tpdbScenes {
// Clear relationships to avoid complexity in auto-import
sc.Performers = nil
sc.Tags = nil
sc.Studio = nil
sc.StudioID = nil
if err := store.Create(&sc); err != nil {
fmt.Printf("⚠ Failed to import %s: %v\n", sc.Title, err)
continue
}
imported++
}
// Search again to get the imported scenes with their IDs
scenes, err = store.Search(query)
if err != nil {
return fmt.Errorf("search failed after import: %w", err)
}
fmt.Printf("✓ Imported %d scene(s) (use 'import scene' for full metadata with relationships)\n\n", imported)
}
fmt.Printf("Found %d scene(s):\n\n", len(scenes))
for _, sc := range scenes {
fmt.Printf("ID: %d\n", sc.ID)

View File

@ -3,16 +3,16 @@ sources:
- name: "tpdb"
baseURL: "https://api.theporndb.net"
apiKey: "${TPDB_API_KEY}"
enabled: true
enabled: false # Temporarily disabled (Adult Empire-only mode)
priority: 1
options:
includeMalePerformers: true
skipMultipleMatches: true
- name: "ae"
baseURL: "https://example-ae.site/api"
baseURL: "https://www.adultempire.com"
apiKey: "${AE_API_KEY}"
enabled: false
enabled: true
priority: 2
options:
includeMalePerformers: true

View File

@ -2,6 +2,8 @@
Complete command-line interface documentation for Goondex.
> TPDB import and sync commands are temporarily disabled. Use Adult Empire commands (prefixed with `goondex adultemp ...`) to search and import new data.
## Global Flags
```bash

View File

@ -565,6 +565,30 @@ type APIResponse struct {
Data interface{} `json:"data,omitempty"`
}
const tpdbEnabled = false
const tpdbDisabledMessage = "TPDB integration is disabled. Use the Adult Empire CLI commands to import and enrich data for now."
func tpdbAPIKey() (string, error) {
if !tpdbEnabled {
return "", fmt.Errorf(tpdbDisabledMessage)
}
apiKey := os.Getenv("TPDB_API_KEY")
if apiKey == "" {
return "", fmt.Errorf("TPDB_API_KEY not configured")
}
return apiKey, nil
}
func writeTPDBError(w http.ResponseWriter, err error) bool {
if err == nil {
return false
}
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: err.Error()})
return true
}
func (s *Server) handleAPIImportPerformer(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
@ -579,9 +603,8 @@ func (s *Server) handleAPIImportPerformer(w http.ResponseWriter, r *http.Request
return
}
apiKey := os.Getenv("TPDB_API_KEY")
if apiKey == "" {
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
apiKey, err := tpdbAPIKey()
if writeTPDBError(w, err) {
return
}
@ -634,9 +657,8 @@ func (s *Server) handleAPIImportStudio(w http.ResponseWriter, r *http.Request) {
return
}
apiKey := os.Getenv("TPDB_API_KEY")
if apiKey == "" {
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
apiKey, err := tpdbAPIKey()
if writeTPDBError(w, err) {
return
}
@ -684,9 +706,8 @@ func (s *Server) handleAPIImportScene(w http.ResponseWriter, r *http.Request) {
return
}
apiKey := os.Getenv("TPDB_API_KEY")
if apiKey == "" {
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
apiKey, err := tpdbAPIKey()
if writeTPDBError(w, err) {
return
}
@ -773,9 +794,8 @@ func (s *Server) handleAPISync(w http.ResponseWriter, r *http.Request) {
}
json.NewDecoder(r.Body).Decode(&req)
apiKey := os.Getenv("TPDB_API_KEY")
if apiKey == "" {
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
apiKey, err := tpdbAPIKey()
if writeTPDBError(w, err) {
return
}
@ -801,6 +821,10 @@ func (s *Server) handleAPISync(w http.ResponseWriter, r *http.Request) {
}
func (s *Server) handleAPISyncStatus(w http.ResponseWriter, r *http.Request) {
if writeTPDBError(w, fmt.Errorf(tpdbDisabledMessage)) {
return
}
scraper := tpdb.NewScraper("https://api.theporndb.net", "")
service := sync.NewService(s.db, scraper)
@ -829,9 +853,8 @@ func (s *Server) handleAPIBulkImportAll(w http.ResponseWriter, r *http.Request)
w.Header().Set("Content-Type", "application/json")
apiKey := os.Getenv("TPDB_API_KEY")
if apiKey == "" {
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
apiKey, err := tpdbAPIKey()
if writeTPDBError(w, err) {
return
}
@ -859,9 +882,8 @@ func (s *Server) handleAPIBulkImportPerformers(w http.ResponseWriter, r *http.Re
w.Header().Set("Content-Type", "application/json")
apiKey := os.Getenv("TPDB_API_KEY")
if apiKey == "" {
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
apiKey, err := tpdbAPIKey()
if writeTPDBError(w, err) {
return
}
@ -889,9 +911,8 @@ func (s *Server) handleAPIBulkImportStudios(w http.ResponseWriter, r *http.Reque
w.Header().Set("Content-Type", "application/json")
apiKey := os.Getenv("TPDB_API_KEY")
if apiKey == "" {
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
apiKey, err := tpdbAPIKey()
if writeTPDBError(w, err) {
return
}
@ -919,9 +940,8 @@ func (s *Server) handleAPIBulkImportScenes(w http.ResponseWriter, r *http.Reques
w.Header().Set("Content-Type", "application/json")
apiKey := os.Getenv("TPDB_API_KEY")
if apiKey == "" {
json.NewEncoder(w).Encode(APIResponse{Success: false, Message: "TPDB_API_KEY not configured"})
apiKey, err := tpdbAPIKey()
if writeTPDBError(w, err) {
return
}
@ -947,9 +967,9 @@ func (s *Server) handleAPIBulkImportPerformersProgress(w http.ResponseWriter, r
w.Header().Set("Connection", "keep-alive")
w.Header().Set("Access-Control-Allow-Origin", "*")
apiKey := os.Getenv("TPDB_API_KEY")
if apiKey == "" {
fmt.Fprintf(w, "data: {\"error\": \"TPDB_API_KEY not configured\"}\n\n")
apiKey, err := tpdbAPIKey()
if err != nil {
fmt.Fprintf(w, "data: {\"error\": \"%s\"}\n\n", err.Error())
return
}
@ -990,9 +1010,9 @@ func (s *Server) handleAPIBulkImportStudiosProgress(w http.ResponseWriter, r *ht
w.Header().Set("Connection", "keep-alive")
w.Header().Set("Access-Control-Allow-Origin", "*")
apiKey := os.Getenv("TPDB_API_KEY")
if apiKey == "" {
fmt.Fprintf(w, "data: {\"error\": \"TPDB_API_KEY not configured\"}\n\n")
apiKey, err := tpdbAPIKey()
if err != nil {
fmt.Fprintf(w, "data: {\"error\": \"%s\"}\n\n", err.Error())
return
}
@ -1033,9 +1053,9 @@ func (s *Server) handleAPIBulkImportScenesProgress(w http.ResponseWriter, r *htt
w.Header().Set("Connection", "keep-alive")
w.Header().Set("Access-Control-Allow-Origin", "*")
apiKey := os.Getenv("TPDB_API_KEY")
if apiKey == "" {
fmt.Fprintf(w, "data: {\"error\": \"TPDB_API_KEY not configured\"}\n\n")
apiKey, err := tpdbAPIKey()
if err != nil {
fmt.Fprintf(w, "data: {\"error\": \"%s\"}\n\n", err.Error())
return
}

View File

@ -507,6 +507,23 @@ main.container {
color: var(--color-brand);
}
.empty-import-actions {
margin-top: 1.5rem;
}
.empty-import-actions .action-buttons {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
justify-content: center;
margin-bottom: 0.75rem;
}
.empty-import-actions .hint {
font-size: 0.95rem;
color: var(--color-text-secondary);
}
/* Detail views */
.breadcrumb {
margin-bottom: 1.5rem;

View File

@ -24,14 +24,15 @@
inkscape:deskcolor="#505050"
inkscape:document-units="px"
inkscape:zoom="2.1896304"
inkscape:cx="898.55348"
inkscape:cy="158.70258"
inkscape:cx="884.39583"
inkscape:cy="34.252356"
inkscape:window-width="1920"
inkscape:window-height="1048"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1">
inkscape:current-layer="g9"
showgrid="false">
<inkscape:page
x="0"
y="0"
@ -48,6 +49,20 @@
id="page2"
margin="0"
bleed="0" />
<inkscape:grid
id="grid3"
units="px"
originx="0"
originy="0"
spacingx="1"
spacingy="1"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
enabled="true"
visible="false" />
</sodipodi:namedview>
<defs
id="defs1" />
@ -58,29 +73,80 @@
<path
id="path26"
style="font-size:48px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans';fill:#ff5fa2;fill-opacity:1;stroke-width:0;stroke-linecap:round;paint-order:markers fill stroke"
d="m 89.6071,50.4885 c -23.10416,0 -39.60743,16.69024 -39.60743,39.51149 0,22.82124 16.50328,39.51151 39.60743,39.51151 22.06683,0 39.04336,-15.65212 39.04336,-37.90755 v -3.39592 h -40.6473 v 8.57996 h 30.08354 c -1.13163,13.67388 -12.63408,23.85962 -28.0997,23.85962 -17.6346,0 -30.08354,-12.82442 -30.08354,-30.64762 0,-17.72891 12.44569,-30.45956 29.89167,-30.45956 12.91947,0 23.57566,7.07122 26.68766,16.59581 h 10.75176 C 123.27385,61.70793 108.84487,50.48851 89.6071,50.4885 Z m 83.73122,0 c -22.91553,0 -39.79544,16.69024 -39.79544,39.51149 0,22.82124 16.97586,39.51151 39.89139,39.51151 11.29137,0 21.11695,-4.05219 28.18029,-10.89376 7.08654,6.84157 16.93497,10.89376 28.22632,10.89376 22.91556,0 39.79544,-16.69026 39.79544,-39.51151 0,-22.82124 -16.97196,-39.51149 -39.88752,-39.51149 -11.29138,0 -21.11698,4.05217 -28.18029,10.89376 -7.08655,-6.84159 -16.9388,-10.89376 -28.23019,-10.89376 z m 156.5227,1.32 v 59.3152 L 284.12556,52.28048 h -9.23996 v 75.53498 h 9.89995 V 68.50023 l 45.73537,58.84324 h 9.3359 V 51.80846 Z m 18.51061,0.47198 v 75.53499 h 26.7796 c 26.0276,0 41.1193,-15.1812 41.1193,-37.71954 0,-0.52548 -0.01,-1.04807 -0.027,-1.56558 -0.041,-1.2646 -0.1283,-2.50346 -0.2647,-3.71824 h -0.01 c -2.2059,-19.60648 -16.8839,-32.53165 -40.82,-32.53165 z m 74.6754,0 v 75.53499 h 54.5072 v -8.77182 h -44.6073 V 93.5839 h 40.4593 v -8.77179 h -40.4593 V 61.04843 h 43.7593 v -8.76795 z m 60.6582,0 26.3116,37.34349 -27.2555,38.1915 h 11.5998 l 21.9717,-30.93156 21.8797,30.93156 h 11.7878 l -27.3476,-38.47545 26.4036,-37.05954 h -11.5039 l -21.0277,29.79956 -20.8436,-29.79956 z m -310.36688,7.25996 c 9.05961,0 16.87419,3.48312 22.25184,9.3704 -3.60762,5.99921 -5.63683,13.17524 -5.63683,21.08915 0,7.89949 2.03062,15.06595 5.64066,21.05848 -5.36636,5.89579 -13.15175,9.40112 -22.15972,9.40112 -17.2574,0 -29.98763,-12.73069 -29.98763,-30.4596 0,-17.8232 12.63428,-30.45955 29.89168,-30.45955 z m 56.41046,0 c 17.25739,0 29.98763,12.63635 29.98763,30.45955 0,17.72891 -12.73244,30.45958 -29.89553,30.45958 -9.05209,0 -16.85927,-3.50401 -22.23648,-9.39344 3.59921,-5.99469 5.62531,-13.16204 5.62531,-21.06614 0,-7.91897 -2.04458,-15.09915 -5.67135,-21.10067 5.35263,-5.88029 13.13673,-9.35888 22.19042,-9.35888 z m 128.52272,1.60391 h 17.1637 c 17.2271,0 28.4182,8.55424 30.4864,23.66776 h -23.3339 v 8.77179 h 23.5335 c 0.098,-1.12825 0.1497,-2.29113 0.1497,-3.48797 0,1.19665 -0.052,2.35989 -0.1497,3.48797 -1.4059,16.20741 -12.7883,25.27173 -30.686,25.27173 h -17.1637 z M 201.58388,79.12157 c 1.1334,3.32559 1.74589,6.97798 1.74589,10.87842 0,3.87376 -0.60919,7.50886 -1.73821,10.82471 -1.13003,-3.31585 -1.73825,-6.95095 -1.73825,-10.82471 0,-3.90044 0.60423,-7.55286 1.73057,-10.87842 z m -28.99762,21.55347 c -2.1037,1.2e-4 -3.80849,1.70661 -3.80647,3.81032 9e-5,2.10223 1.70425,3.80637 3.80647,3.80649 2.10221,-1.2e-4 3.80637,-1.70426 3.80651,-3.80649 0.002,-2.10371 -1.70281,-3.8102 -3.80651,-3.81032 z m 56.4642,0 c -2.10372,1.2e-4 -3.80849,1.70661 -3.80651,3.81032 1.3e-4,2.10223 1.70425,3.80637 3.80651,3.80649 2.10222,-1.2e-4 3.80637,-1.70426 3.80649,-3.80649 0.002,-2.10371 -1.70279,-3.8102 -3.80649,-3.81032 z" />
d="m 89.6071,50.4885 c -23.10416,0 -39.60743,16.69024 -39.60743,39.51149 0,22.82124 16.50328,39.51151 39.60743,39.51151 22.06683,0 39.04336,-15.65212 39.04336,-37.90755 v -3.39592 h -40.6473 v 8.57996 h 30.08354 c -1.13163,13.67388 -12.63408,23.85962 -28.0997,23.85962 -17.6346,0 -30.08354,-12.82442 -30.08354,-30.64762 0,-17.72891 12.44569,-30.45956 29.89167,-30.45956 12.91947,0 23.57566,7.07122 26.68766,16.59581 h 10.75176 C 123.27385,61.70793 108.84487,50.48851 89.6071,50.4885 Z m 240.25392,1.32 v 59.3152 L 284.12556,52.28048 h -9.23996 v 75.53498 h 9.89995 V 68.50023 l 45.73537,58.84324 h 9.3359 V 51.80846 Z m 18.51061,0.47198 v 75.53499 h 26.7796 c 26.0276,0 41.1193,-15.1812 41.1193,-37.71954 0,-0.52548 -0.01,-1.04807 -0.027,-1.56558 -0.041,-1.2646 -0.1283,-2.50346 -0.2647,-3.71824 h -0.01 c -2.2059,-19.60648 -16.8839,-32.53165 -40.82,-32.53165 z m 74.6754,0 v 75.53499 h 54.5072 v -8.77182 h -44.6073 V 93.5839 h 40.4593 v -8.77179 h -40.4593 V 61.04843 h 43.7593 v -8.76795 z m 60.6582,0 26.3116,37.34349 -27.2555,38.1915 h 11.5998 l 21.9717,-30.93156 21.8797,30.93156 h 11.7878 l -27.3476,-38.47545 26.4036,-37.05954 h -11.5039 l -21.0277,29.79956 -20.8436,-29.79956 z m -125.4337,8.86387 h 17.1637 c 17.2271,0 28.4182,8.55424 30.4864,23.66776 h -23.3339 v 8.77179 h 23.5335 c 0.098,-1.12825 0.1497,-2.29113 0.1497,-3.48797 0,1.19665 -0.052,2.35989 -0.1497,3.48797 -1.4059,16.20741 -12.7883,25.27173 -30.686,25.27173 h -17.1637 z"
sodipodi:nodetypes="ssssccccsssccscccccccccccccsscccsccccccccccccccccccccccccccccsccccccscc" />
<path
d="m 206.54093,52.264773 h -9.90177 v 75.536347 h 9.90177 z"
style="font-size:86.3973px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans, Normal';display:none;fill:#808000;stroke-width:7.85855"
id="path3" />
</g>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="OG_Titty"
style="display:none">
<path
d="m 173.33832,50.4885 c -22.91553,0 -39.79544,16.69024 -39.79544,39.51149 0,22.82124 16.97586,39.51151 39.89139,39.51151 11.29137,0 21.11695,-4.05219 28.18029,-10.89376 7.08654,6.84157 16.93497,10.89376 28.22632,10.89376 22.91556,0 39.79544,-16.69026 39.79544,-39.51151 0,-22.82124 -16.97196,-39.51149 -39.88752,-39.51149 -11.29138,0 -21.11698,4.05217 -28.18029,10.89376 -7.08655,-6.84159 -16.9388,-10.89376 -28.23019,-10.89376 z m 3e-5,9.05194 c 9.05961,0 16.87419,3.48312 22.25184,9.3704 -3.60762,5.99921 -5.63683,13.17524 -5.63683,21.08915 0,7.89949 2.03062,15.06595 5.64066,21.05848 -5.36636,5.89579 -13.15175,9.40112 -22.15972,9.40112 -17.2574,0 -29.98763,-12.73069 -29.98763,-30.4596 0,-17.8232 12.63428,-30.45955 29.89168,-30.45955 z m 56.41046,0 c 17.25739,0 29.98763,12.63635 29.98763,30.45955 0,17.72891 -12.73244,30.45958 -29.89553,30.45958 -9.05209,0 -16.85927,-3.50401 -22.23648,-9.39344 3.59921,-5.99469 5.62531,-13.16204 5.62531,-21.06614 0,-7.91897 -2.04458,-15.09915 -5.67135,-21.10067 5.35263,-5.88029 13.13673,-9.35888 22.19042,-9.35888 z m -28.16493,19.58113 c 1.1334,3.32559 1.74589,6.97798 1.74589,10.87842 0,3.87376 -0.60919,7.50886 -1.73821,10.82471 -1.13003,-3.31585 -1.73825,-6.95095 -1.73825,-10.82471 0,-3.90044 0.60423,-7.55286 1.73057,-10.87842 z m -28.99762,21.55347 c -2.1037,1.2e-4 -3.80849,1.70661 -3.80647,3.81032 9e-5,2.10223 1.70425,3.80637 3.80647,3.80649 2.10221,-1.2e-4 3.80637,-1.70426 3.80651,-3.80649 0.002,-2.10371 -1.70281,-3.8102 -3.80651,-3.81032 z m 56.4642,0 c -2.10372,1.2e-4 -3.80849,1.70661 -3.80651,3.81032 1.3e-4,2.10223 1.70425,3.80637 3.80651,3.80649 2.10222,-1.2e-4 3.80637,-1.70426 3.80649,-3.80649 0.002,-2.10371 -1.70279,-3.8102 -3.80649,-3.81032 z"
style="font-size:48px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans';fill:#ff5fa2;fill-opacity:1;stroke-width:0;stroke-linecap:round;paint-order:markers fill stroke"
id="path1-6"
sodipodi:nodetypes="ssscssscsscscsssssscscscscsccccccccccc" />
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="Titty"
style="display:none">
<path
d="m 173.43286,129.49856 c 22.91553,0 39.79568,-16.69155 39.79568,-39.512767 0,-22.82121 -16.97446,-39.512769 -39.88998,-39.512769 -22.91552,0 -39.79568,16.691559 -39.79568,39.512769 0,22.821217 16.97447,39.512767 39.88998,39.512767 z m 0,-9.05304 c -17.25736,0 -29.98821,-12.73084 -29.98821,-30.459727 0,-17.823182 12.63655,-30.459726 29.89391,-30.459726 17.25737,0 29.98822,12.636544 29.98822,30.459726 0,17.728887 -12.73085,30.459727 -29.89392,30.459727 z"
id="text3"
style="font-size:86.3973px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans, Normal';stroke-width:7.85855"
aria-label="OOI"
sodipodi:nodetypes="ssssssssss" />
<path
d="m 229.84152,129.49856 c 22.91553,0 39.79567,-16.69155 39.79567,-39.512767 0,-22.82121 -16.97445,-39.512769 -39.88998,-39.512769 -22.91551,0 -39.79567,16.691559 -39.79567,39.512769 0,22.821217 16.97446,39.512767 39.88998,39.512767 z m 0,-9.05304 c -17.25736,0 -29.98821,-12.73084 -29.98821,-30.459727 0,-17.823182 12.63654,-30.459726 29.8939,-30.459726 17.25737,0 29.98822,12.636544 29.98822,30.459726 0,17.728887 -12.73085,30.459727 -29.89391,30.459727 z"
style="font-size:86.3973px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans, Normal';stroke-width:7.85855"
id="path1-5"
sodipodi:nodetypes="ssssssssss" />
<path
d="m 206.54093,52.264773 h -9.90177 v 75.536347 h 9.90177 z"
style="font-size:86.3973px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans, Normal';stroke-width:7.85855"
id="path1-10" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Layer 2">
<path
d="m 699.60709,50.4885 c -23.10416,0 -39.60742,16.69024 -39.60742,39.51149 0,22.82124 16.50328,39.51151 39.60742,39.51151 22.06684,0 39.04337,-15.65212 39.04337,-37.90755 v -3.39592 h -40.64731 v 8.57996 h 30.08355 c -1.13164,13.67388 -12.63408,23.85962 -28.09971,23.85962 -17.6346,0 -30.08354,-12.82442 -30.08354,-30.64762 0,-17.72891 12.4457,-30.45956 29.89167,-30.45956 12.91948,0 23.57567,7.07122 26.68767,16.59581 h 10.75176 C 733.27385,61.70793 718.84487,50.48851 699.60709,50.4885 Z m 83.73123,0 c -22.91553,0 -39.79545,16.69024 -39.79545,39.51149 0,22.82124 16.97586,39.51151 39.89139,39.51151 11.29137,0 21.11696,-4.05219 28.18029,-10.89376 7.08654,6.84157 16.93497,10.89376 28.22632,10.89376 22.91556,0 39.79545,-16.69026 39.79545,-39.51151 0,-22.82124 -16.97197,-39.51149 -39.88752,-39.51149 -11.29139,0 -21.11698,4.05217 -28.18029,10.89376 C 804.48196,54.54067 794.6297,50.4885 783.33832,50.4885 Z m 156.5227,1.32 v 59.3152 L 894.12555,52.28048 h -9.23995 v 75.53498 h 9.89995 V 68.50023 l 45.73536,58.84324 h 9.3359 V 51.80846 Z m -156.52268,7.73194 c 9.05962,0 16.87419,3.48312 22.25184,9.3704 -3.60761,5.99921 -5.63683,13.17524 -5.63683,21.08915 0,7.89949 2.03062,15.06595 5.64066,21.05848 -5.36635,5.89579 -13.15175,9.40112 -22.15972,9.40112 -17.25739,0 -29.98762,-12.73069 -29.98762,-30.4596 0,-17.8232 12.63428,-30.45955 29.89167,-30.45955 z m 56.41047,0 c 17.25739,0 29.98763,12.63635 29.98763,30.45955 0,17.72891 -12.73244,30.45958 -29.89553,30.45958 -9.0521,0 -16.85928,-3.50401 -22.23649,-9.39344 3.59921,-5.99469 5.62531,-13.16204 5.62531,-21.06614 0,-7.91897 -2.04458,-15.09915 -5.67134,-21.10067 5.35262,-5.88029 13.13673,-9.35888 22.19042,-9.35888 z m -28.16493,19.58113 c 1.13339,3.32559 1.74589,6.97798 1.74589,10.87842 0,3.87376 -0.6092,7.50886 -1.73822,10.82471 -1.13002,-3.31585 -1.73825,-6.95095 -1.73825,-10.82471 0,-3.90044 0.60423,-7.55286 1.73058,-10.87842 z"
d="m 699.60709,50.4885 c -23.10416,0 -39.60742,16.69024 -39.60742,39.51149 0,22.82124 16.50328,39.51151 39.60742,39.51151 22.06684,0 39.04337,-15.65212 39.04337,-37.90755 v -3.39592 h -40.64731 v 8.57996 h 30.08355 c -1.13164,13.67388 -12.63408,23.85962 -28.09971,23.85962 -17.6346,0 -30.08354,-12.82442 -30.08354,-30.64762 0,-17.72891 12.4457,-30.45956 29.89167,-30.45956 12.91948,0 23.57567,7.07122 26.68767,16.59581 h 10.75176 C 733.27385,61.70793 718.84487,50.48851 699.60709,50.4885 Z m 240.25393,1.32 v 59.3152 L 894.12555,52.28048 h -9.23995 v 75.53498 h 9.89995 V 68.50023 l 45.73536,58.84324 h 9.3359 V 51.80846 Z"
style="font-size:48px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans';fill:#483737;fill-opacity:1;stroke-width:0;stroke-linecap:round;paint-order:markers fill stroke"
id="path1"
sodipodi:nodetypes="ssssccccsssccsssscssscscccccccccccscscsssssscscscscsc" />
sodipodi:nodetypes="ssssccccsssccsccccccccccc" />
<path
id="path2"
style="font-size:48px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans';fill:#8a6f91;fill-opacity:1;stroke-width:0;stroke-linecap:round;paint-order:markers fill stroke"
d="m 958.37162,52.28048 v 75.53499 h 26.7796 c 26.02758,0 41.11928,-15.1812 41.11928,-37.71954 0,-0.52548 -0.01,-1.04807 -0.027,-1.56558 -0.041,-1.2646 -0.1283,-2.50346 -0.2647,-3.71824 h -0.01 c -2.2059,-19.60648 -16.8839,-32.53165 -40.81997,-32.53165 z m 9.8999,8.86387 h 17.16371 c 17.22707,0 28.41817,8.55424 30.48637,23.66776 h -23.33388 v 8.77179 h 23.53348 c 0.098,-1.12825 0.1497,-2.29113 0.1497,-3.48797 0,1.19665 -0.052,2.35989 -0.1497,3.48797 -1.4059,16.20741 -12.7883,25.27173 -30.68597,25.27173 h -17.16371 z"
sodipodi:nodetypes="ccsscccsccsccccccscc" />
</g>
<path
d="m 782.58626,100.67504 c -2.10371,1.2e-4 -3.8085,1.70661 -3.80647,3.81032 9e-5,2.10223 1.70425,3.80637 3.80647,3.80649 2.10221,-1.2e-4 3.80636,-1.70426 3.8065,-3.80649 0.002,-2.10371 -1.70281,-3.8102 -3.8065,-3.81032 z m 56.46419,0 c -2.10372,1.2e-4 -3.80848,1.70661 -3.8065,3.81032 1.2e-4,2.10223 1.70425,3.80637 3.8065,3.80649 2.10222,-1.2e-4 3.80637,-1.70426 3.80649,-3.80649 0.002,-2.10371 -1.70278,-3.8102 -3.80649,-3.81032 z"
style="font-size:48px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans';fill:#8a6f91;fill-opacity:1;stroke-width:0;stroke-linecap:round;paint-order:markers fill stroke"
id="path1-9" />
<path
d="m 1033.047,52.28048 v 75.53499 h 54.5072 v -8.77182 h -44.6073 V 93.5839 h 40.4593 v -8.77179 h -40.4593 V 61.04843 h 43.7593 v -8.76795 z m 60.6582,0 26.3116,37.34349 -27.2555,38.1915 h 11.5998 l 21.9717,-30.93156 21.8797,30.93156 h 11.7878 l -27.3476,-38.47545 26.4036,-37.05954 h -11.5039 l -21.0277,29.79956 -20.8436,-29.79956 z"
style="font-size:48px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans';fill:#ff5fa2;fill-opacity:1;stroke-width:0;stroke-linecap:round;paint-order:markers fill stroke"
id="path1-1" />
<g
inkscape:groupmode="layer"
id="g9"
inkscape:label="Titty">
<path
id="path13"
style="font-size:86.3973px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans, Normal';stroke-width:7.85855;fill:#ff5fa2;fill-opacity:1"
d="M 173.33789 50.472656 C 150.42237 50.472656 133.54297 67.165118 133.54297 89.986328 C 133.54297 112.80755 150.51808 129.49805 173.43359 129.49805 C 184.72527 129.49805 194.54994 125.44543 201.61328 118.60352 C 208.69985 125.44543 218.55013 129.49805 229.8418 129.49805 C 252.75733 129.49805 269.63672 112.80755 269.63672 89.986328 C 269.63672 67.165118 252.66358 50.472656 229.74805 50.472656 C 218.45638 50.472656 208.62975 54.525269 201.56641 61.367188 C 194.47983 54.525267 184.62956 50.472656 173.33789 50.472656 z M 173.33789 59.525391 C 182.39788 59.525391 190.21021 63.008763 195.58789 68.896484 C 198.21228 71.769779 200.25728 75.215888 201.58398 79.109375 C 202.9042 75.210676 204.94121 71.760371 207.55859 68.884766 C 212.91125 63.004031 220.69398 59.525391 229.74805 59.525391 C 247.00542 59.525391 259.73633 72.163146 259.73633 89.986328 C 259.73633 107.71522 247.00486 120.44531 229.8418 120.44531 C 220.78934 120.44531 212.98272 116.94263 207.60547 111.05273 C 204.97114 108.16726 202.91866 104.70856 201.58984 100.80859 C 200.2638 104.70381 198.21994 108.15962 195.5957 111.04297 C 190.22932 116.93923 182.44196 120.44531 173.43359 120.44531 C 156.17623 120.44531 143.44531 107.71522 143.44531 89.986328 C 143.44531 72.163146 156.08053 59.525391 173.33789 59.525391 z M 172.58594 100.67578 C 170.48224 100.6759 168.77728 102.38262 168.7793 104.48633 C 168.77939 106.58856 170.48372 108.2909 172.58594 108.29102 C 174.68815 108.2909 176.39244 106.58856 176.39258 104.48633 C 176.39458 102.38262 174.68964 100.6759 172.58594 100.67578 z M 229.05078 100.67578 C 226.94706 100.6759 225.24216 102.38262 225.24414 104.48633 C 225.24427 106.58856 226.94852 108.2909 229.05078 108.29102 C 231.153 108.2909 232.8573 106.58856 232.85742 104.48633 C 232.85942 102.38262 231.15448 100.6759 229.05078 100.67578 z " />
<path
id="path19"
style="font-size:86.3973px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans, Normal';fill:#483737;fill-opacity:1;stroke-width:7.85855"
d="m 783.33779,50.472656 c -22.91552,0 -39.79492,16.692462 -39.79492,39.513672 0,22.821222 16.97511,39.511722 39.89062,39.511722 11.29168,0 21.11635,-4.05262 28.17969,-10.89453 7.08657,6.84191 16.93685,10.89453 28.22852,10.89453 22.91553,0 39.79492,-16.6905 39.79492,-39.511722 0,-22.82121 -16.97314,-39.513672 -39.88867,-39.513672 -11.29167,0 -21.1183,4.052613 -28.18164,10.894532 -7.08658,-6.841921 -16.93685,-10.894532 -28.22852,-10.894532 z m 0,9.052735 c 9.05999,0 16.87232,3.483372 22.25,9.371093 2.62439,2.873295 4.66939,6.319404 5.99609,10.212891 1.32022,-3.898699 3.35723,-7.349004 5.97461,-10.224609 5.35266,-5.880735 13.13539,-9.359375 22.18946,-9.359375 17.25737,0 29.98828,12.637755 29.98828,30.460937 0,17.728892 -12.73147,30.458982 -29.89453,30.458982 -9.05246,0 -16.85908,-3.50268 -22.23633,-9.39258 -2.63433,-2.88547 -4.68681,-6.34417 -6.01563,-10.24414 -1.32604,3.89522 -3.3699,7.35103 -5.99414,10.23438 -5.36638,5.89626 -13.15374,9.40234 -22.16211,9.40234 -17.25736,0 -29.98828,-12.73009 -29.98828,-30.458982 0,-17.823182 12.63522,-30.460937 29.89258,-30.460937 z"
sodipodi:nodetypes="ssscssscssscssssscssss" />
<path
d="m 782.58584,100.67578 c -2.1037,1.2e-4 -3.80866,1.70684 -3.80664,3.81055 9e-5,2.10223 1.70442,3.80457 3.80664,3.80469 2.10221,-1.2e-4 3.8065,-1.70246 3.80664,-3.80469 0.002,-2.10371 -1.70294,-3.81043 -3.80664,-3.81055 z m 56.46484,0 c -2.10372,1.2e-4 -3.80862,1.70684 -3.80664,3.81055 1.3e-4,2.10223 1.70438,3.80457 3.80664,3.80469 2.10222,-1.2e-4 3.80652,-1.70246 3.80664,-3.80469 0.002,-2.10371 -1.70294,-3.81043 -3.80664,-3.81055 z"
style="font-size:86.3973px;font-family:'Gmarket Sans';-inkscape-font-specification:'Gmarket Sans, Normal';fill:#8a6f91;fill-opacity:1;stroke-width:7.85855"
id="path1-52" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -244,10 +244,37 @@ async function bulkImportScenes() {
};
}
function bulkImportMovies() {
alert('Bulk movie import is not implemented yet. Use the Adult Empire CLI to scrape movies individually for now.');
}
function toggleFilterbar() {
document.getElementById('filterbar').classList.toggle('open');
}
function showTPDBDisabled() {
alert('TPDB import/sync is temporarily disabled. Use Adult Empire CLI commands instead:\n\n' +
' ./goondex adultemp search-performer "Name"\n' +
' ./goondex adultemp scrape-performer <url>\n' +
' ./goondex adultemp search-scene "Title"\n' +
' ./goondex adultemp scrape-scene <url>');
}
function scrollToAEImport() {
const section = document.getElementById('ae-import');
if (section) {
section.scrollIntoView({ behavior: 'smooth' });
}
}
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
alert('Copied to clipboard:\n' + text);
}).catch(() => {
alert('Could not copy. Please copy manually:\n' + text);
});
}
function applyFilters() {
// Hook for your search/filter logic
console.log("Applying filters…");

View File

@ -93,16 +93,16 @@
<!-- HERO -->
<section class="hero-section">
<h1 class="hero-title">Welcome to Goondex</h1>
<p class="hero-subtitle">Your professional adult media indexer powered by ThePornDB</p>
<p class="hero-subtitle">Adult Empire-first indexer (TPDB temporarily disabled)</p>
<div class="hero-actions">
<button class="btn" onclick="openModal('import-all-modal')">
Get Started
<button class="btn" onclick="scrollToAEImport()">
Get Started (Adult Empire)
<div class="hoverEffect"><div></div></div>
</button>
<button class="btn-secondary" onclick="openModal('sync-modal')">
Sync Data
<button class="btn-secondary" onclick="showTPDBDisabled()">
TPDB Sync (Disabled)
<div class="hoverEffect"><div></div></div>
</button>
</div>
@ -126,8 +126,8 @@
</div>
<div class="stat-actions">
<a href="/performers" class="stat-link">View all →</a>
<button class="btn-small" onclick="bulkImportPerformers()">
Import All
<button class="btn-small" onclick="scrollToAEImport()">
Import via CLI
<div class="hoverEffect"><div></div></div>
</button>
</div>
@ -142,8 +142,8 @@
</div>
<div class="stat-actions">
<a href="/studios" class="stat-link">View all →</a>
<button class="btn-small" onclick="bulkImportStudios()">
Import All
<button class="btn-small" onclick="scrollToAEImport()">
Import via CLI
<div class="hoverEffect"><div></div></div>
</button>
</div>
@ -158,8 +158,8 @@
</div>
<div class="stat-actions">
<a href="/scenes" class="stat-link">View all →</a>
<button class="btn-small" onclick="bulkImportScenes()">
Import All
<button class="btn-small" onclick="scrollToAEImport()">
Import via CLI
<div class="hoverEffect"><div></div></div>
</button>
</div>
@ -180,51 +180,37 @@
<!-- IMPORT SECTION -->
<section class="import-section">
<h3>Import from ThePornDB</h3>
<h3 id="ae-import">Import from Adult Empire (CLI)</h3>
<p class="help-text">
Import ALL data from ThePornDB. This downloads performers, studios, scenes, and metadata.
TPDB bulk import is temporarily disabled. Use the Adult Empire CLI to seed your library with high-quality mainstream data:
</p>
<div class="import-buttons">
<button class="btn" onclick="openModal('import-all-modal')">
Import Everything
<button class="btn-secondary" onclick="copyToClipboard('./goondex adultemp search-performer \"Name\"')">
Copy: Search Performer
<div class="hoverEffect"><div></div></div>
</button>
<button class="btn-secondary" onclick="bulkImportPerformers()">
Import All Performers
<button class="btn-secondary" onclick="copyToClipboard('./goondex adultemp scrape-performer <url>')">
Copy: Import Performer
<div class="hoverEffect"><div></div></div>
</button>
<button class="btn-secondary" onclick="bulkImportStudios()">
Import All Studios
<button class="btn-secondary" onclick="copyToClipboard('./goondex adultemp search-scene \"Title\"')">
Copy: Search Scene
<div class="hoverEffect"><div></div></div>
</button>
<button class="btn-secondary" onclick="bulkImportScenes()">
Import All Scenes
<button class="btn-secondary" onclick="copyToClipboard('./goondex adultemp scrape-scene <url>')">
Copy: Import Scene
<div class="hoverEffect"><div></div></div>
</button>
</div>
<p class="help-text search-help">Or search for specific items:</p>
<p class="help-text">
Movies: scraper not finished yet. Use scene/performer imports for now.
</p>
<div class="import-buttons">
<button class="btn-secondary" onclick="openModal('search-performer-modal')">
Search Performer
<div class="hoverEffect"><div></div></div>
</button>
<button class="btn-secondary" onclick="openModal('search-studio-modal')">
Search Studio
<div class="hoverEffect"><div></div></div>
</button>
<button class="btn-secondary" onclick="openModal('search-scene-modal')">
Search Scene
<div class="hoverEffect"><div></div></div>
</button>
</div>
<p class="help-text">
Bulk “Import All” buttons will stay disabled until an Adult Empire bulk flow is available.
</p>
</section>
</main>

View File

@ -65,11 +65,19 @@
{{else}}
<div class="empty-state">
<p>No performers found.</p>
{{if .Query}}
<p>Try a different search term or <a href="/performers">view all performers</a>.</p>
{{else}}
<p>Import performers using the dashboard or CLI: <code>./goondex import performer "name"</code></p>
{{end}}
<div class="empty-import-actions">
<p class="hint">Kick off a bulk import to seed your library.</p>
<div class="action-buttons">
<button type="button" class="btn" onclick="showTPDBDisabled()">Import all performers</button>
<button type="button" class="btn btn-secondary" onclick="showTPDBDisabled()">Import all studios</button>
<button type="button" class="btn btn-secondary" onclick="showTPDBDisabled()">Import all scenes</button>
<button type="button" class="btn btn-secondary" onclick="bulkImportMovies()">Import all movies</button>
</div>
<p class="hint">
Bulk import currently targets TPDB endpoints (disabled). Adult Empire bulk import will be added soon.
For Adult Empire now, use CLI to pick targets: <code>./goondex adultemp search-performer "Name"</code> then <code>./goondex adultemp scrape-performer &lt;url&gt;</code>.
</p>
</div>
</div>
{{end}}
</main>

1956
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,11 @@
{
"name": "goondex",
"version": "0.1.0-dev5",
"description": "Goondex web development environment",
"scripts": {
"dev": "air",
"build": "go build -o ./bin/goondex ./cmd/goondex"
},
"dependencies": {
"bootstrap": "^5.3.8"
}

16
scripts/build.sh Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$ROOT/scripts/env.sh"
GO_BUILD_FLAGS=${GO_BUILD_FLAGS:-"-v"}
if [[ "${QUIET:-0}" == "1" ]]; then
GO_BUILD_FLAGS=""
fi
mkdir -p "$ROOT/bin"
echo "Building Goondex (Adult Empire-only mode)..."
echo "go build ${GO_BUILD_FLAGS} -o $ROOT/bin/goondex $ROOT/cmd/goondex"
go build ${GO_BUILD_FLAGS} -o "$ROOT/bin/goondex" "$ROOT/cmd/goondex"
echo "Built: $ROOT/bin/goondex"

15
scripts/env.sh Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Source this to pin Go caches inside the repo (avoids home-level permission issues).
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
echo "Source this script: source scripts/env.sh" >&2
exit 1
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
export GOPATH="$ROOT/tmp/go"
export GOMODCACHE="$GOPATH/pkg/mod"
export GOCACHE="$ROOT/tmp/.gocache"
mkdir -p "$ROOT/tmp/go" "$ROOT/tmp/.gocache"

15
scripts/run-web.sh Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$ROOT/scripts/env.sh"
ADDR="${ADDR:-localhost:8080}"
if [[ ! -x "$ROOT/bin/goondex" ]]; then
echo "Binary not found; building first..."
"$ROOT/scripts/build.sh"
fi
echo "Starting Goondex web UI on http://$ADDR"
"$ROOT/bin/goondex" web --addr "$ADDR"

16
scripts/run.sh Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$ROOT/scripts/env.sh"
ADDR="${ADDR:-localhost:8788}"
# Build if missing
if [[ ! -x "$ROOT/bin/goondex" ]]; then
echo "Binary not found; building first..."
"$ROOT/scripts/build.sh"
fi
echo "Starting Goondex web UI on http://$ADDR"
"$ROOT/bin/goondex" web --addr "$ADDR"

8
scripts/test.sh Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$ROOT/scripts/env.sh"
echo "Running focused tests (./cmd/... ./internal/...)"
go test ./cmd/... ./internal/...