mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-20 11:33:40 +02:00
chore: archive inactive projects to apps-archived/
Move inactive projects out of active workspace: - bauntown (community website) - maerchenzauber (AI story generation) - memoro (voice memo app) - news (news aggregation) - nutriphi (nutrition tracking) - reader (reading app) - uload (URL shortener) - wisekeep (AI wisdom extraction) Update CLAUDE.md documentation: - Add presi to active projects - Document archived projects section - Update workspace configuration Archived apps can be re-activated by moving back to apps/ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
b97149ac12
commit
61d181fbc2
3148 changed files with 437 additions and 46640 deletions
|
|
@ -0,0 +1,126 @@
|
|||
# Browser Extension für URL-Extraktion
|
||||
|
||||
## Konzept
|
||||
|
||||
Eine Browser Extension kann direkt auf den gerenderten Content zugreifen, nachdem der Nutzer Cookies akzeptiert hat.
|
||||
|
||||
## Implementation (Chrome/Safari)
|
||||
|
||||
### Manifest.json
|
||||
|
||||
```json
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Reader App Extractor",
|
||||
"permissions": ["activeTab", "clipboardWrite"],
|
||||
"action": {
|
||||
"default_popup": "popup.html"
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["<all_urls>"],
|
||||
"js": ["content.js"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Content Script
|
||||
|
||||
```javascript
|
||||
// content.js
|
||||
function extractArticle() {
|
||||
// Nutze Readability direkt im Browser
|
||||
const documentClone = document.cloneNode(true);
|
||||
const reader = new Readability(documentClone);
|
||||
const article = reader.parse();
|
||||
|
||||
if (article) {
|
||||
// Sende an Reader App
|
||||
const readerUrl = `reader-app://add?title=${encodeURIComponent(article.title)}&content=${encodeURIComponent(article.content)}`;
|
||||
window.location.href = readerUrl;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Integration in React Native
|
||||
|
||||
```typescript
|
||||
// Deep Link Handler
|
||||
import { Linking } from 'react-native';
|
||||
|
||||
Linking.addEventListener('url', (event) => {
|
||||
const url = new URL(event.url);
|
||||
if (url.protocol === 'reader-app:' && url.pathname === 'add') {
|
||||
const title = url.searchParams.get('title');
|
||||
const content = url.searchParams.get('content');
|
||||
// Erstelle neuen Text
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## iOS Share Extension Alternative
|
||||
|
||||
### Info.plist
|
||||
|
||||
```xml
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionAttributes</key>
|
||||
<dict>
|
||||
<key>NSExtensionActivationRule</key>
|
||||
<string>SUBQUERY(extensionItems, $e, SUBQUERY($e.attachments, $a, $a.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url").@count > 0).@count > 0</string>
|
||||
</dict>
|
||||
</dict>
|
||||
```
|
||||
|
||||
### Share Extension Code
|
||||
|
||||
```swift
|
||||
import MobileCoreServices
|
||||
|
||||
class ShareViewController: UIViewController {
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
if let item = extensionContext?.inputItems.first as? NSExtensionItem,
|
||||
let provider = item.attachments?.first {
|
||||
|
||||
if provider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
|
||||
provider.loadItem(forTypeIdentifier: kUTTypeURL as String) { (url, error) in
|
||||
if let shareURL = url as? URL {
|
||||
// Extrahiere Content mit WKWebView
|
||||
self.extractContent(from: shareURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func extractContent(from url: URL) {
|
||||
let webView = WKWebView()
|
||||
webView.load(URLRequest(url: url))
|
||||
|
||||
// Nach dem Laden JavaScript ausführen
|
||||
webView.evaluateJavaScript("document.body.innerText") { (result, error) in
|
||||
if let text = result as? String {
|
||||
// Speichere in App Group oder sende an App
|
||||
self.saveToApp(title: url.host ?? "Artikel", content: text, url: url.absoluteString)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Vorteile
|
||||
|
||||
1. Umgeht alle Cookie-Banner (Nutzer akzeptiert im Browser)
|
||||
2. Zugriff auf den vollständig gerenderten Content
|
||||
3. Native Integration in iOS/Android Share-Menü
|
||||
4. Kein Server-Side Rendering nötig
|
||||
|
||||
## Nachteile
|
||||
|
||||
1. Zusätzliche Installation erforderlich
|
||||
2. Platform-spezifische Entwicklung
|
||||
3. App Store Review Process für Extensions
|
||||
300
apps-archived/reader/apps/mobile/docs/deployment-guide.md
Normal file
300
apps-archived/reader/apps/mobile/docs/deployment-guide.md
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
# Reader App - Deployment Guide
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
1. **Google Cloud Account** mit aktivierter Text-to-Speech API
|
||||
2. **Supabase Projekt** mit konfigurierter Datenbank
|
||||
3. **Expo Developer Account** (für App Store Deployment)
|
||||
|
||||
## 1. Google Cloud Setup
|
||||
|
||||
### API Key erstellen
|
||||
|
||||
1. Google Cloud Console → "APIs & Services" → "Credentials"
|
||||
2. "Create Credentials" → "API Key"
|
||||
3. API Key auf Text-to-Speech API beschränken
|
||||
|
||||
### Stimmen konfigurieren
|
||||
|
||||
Die App verwendet Google Neural2 Stimmen:
|
||||
|
||||
- `de-DE-Neural2-A` (Deutsch, weiblich)
|
||||
- `en-US-Neural2-A` (Englisch US, männlich)
|
||||
- `en-GB-Neural2-A` (Englisch UK, weiblich)
|
||||
|
||||
## 2. Supabase Setup
|
||||
|
||||
### Datenbank Migrationen
|
||||
|
||||
```bash
|
||||
# Migrations ausführen
|
||||
supabase migration up
|
||||
|
||||
# Oder manuell in SQL Editor:
|
||||
# - supabase/migrations/20240116_create_texts_table.sql
|
||||
# - supabase/migrations/20240117_create_audio_storage.sql
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
In Supabase Dashboard → Settings → Edge Functions:
|
||||
|
||||
```
|
||||
GOOGLE_TTS_API_KEY=your_google_api_key_here
|
||||
```
|
||||
|
||||
### Edge Functions deployen
|
||||
|
||||
```bash
|
||||
# Supabase CLI installieren
|
||||
npm install -g supabase
|
||||
|
||||
# Edge Functions deployen
|
||||
supabase functions deploy generate-audio
|
||||
supabase functions deploy get-audio-url
|
||||
```
|
||||
|
||||
### Storage Setup
|
||||
|
||||
- Bucket "audio" wird automatisch erstellt
|
||||
- RLS Policies sind konfiguriert
|
||||
- Benutzer können nur ihre eigenen Audio-Dateien zugreifen
|
||||
|
||||
## 3. React Native App Setup
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Erstelle `.env.local`:
|
||||
|
||||
```
|
||||
EXPO_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
|
||||
EXPO_PUBLIC_SUPABASE_ANON_KEY=your_anon_key
|
||||
```
|
||||
|
||||
### Dependencies installieren
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### App konfigurieren
|
||||
|
||||
In `app.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"expo": {
|
||||
"name": "Reader",
|
||||
"slug": "reader",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"userInterfaceStyle": "light",
|
||||
"splash": {
|
||||
"image": "./assets/splash.png",
|
||||
"resizeMode": "contain",
|
||||
"backgroundColor": "#ffffff"
|
||||
},
|
||||
"ios": {
|
||||
"supportsTablet": true,
|
||||
"bundleIdentifier": "com.tilljs.reader"
|
||||
},
|
||||
"android": {
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/adaptive-icon.png",
|
||||
"backgroundColor": "#ffffff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. Development Testing
|
||||
|
||||
### Lokal testen
|
||||
|
||||
```bash
|
||||
# Development Server starten
|
||||
npm start
|
||||
|
||||
# iOS Simulator
|
||||
npm run ios
|
||||
|
||||
# Android Emulator
|
||||
npm run android
|
||||
```
|
||||
|
||||
### Edge Functions testen
|
||||
|
||||
```bash
|
||||
# Lokal
|
||||
supabase functions serve
|
||||
|
||||
# Test Audio Generation
|
||||
curl -X POST 'http://localhost:54321/functions/v1/generate-audio' \
|
||||
-H 'Authorization: Bearer YOUR_SUPABASE_JWT' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"textId": "test-id",
|
||||
"content": "Dies ist ein Test für die Audio-Generierung.",
|
||||
"voice": "de-DE",
|
||||
"speed": 1.0
|
||||
}'
|
||||
```
|
||||
|
||||
## 5. Production Deployment
|
||||
|
||||
### EAS Build Setup
|
||||
|
||||
```bash
|
||||
# EAS CLI installieren
|
||||
npm install -g @expo/eas-cli
|
||||
|
||||
# EAS initialisieren
|
||||
eas init
|
||||
|
||||
# Build konfigurieren
|
||||
eas build:configure
|
||||
```
|
||||
|
||||
### Build Profile (`eas.json`)
|
||||
|
||||
```json
|
||||
{
|
||||
"cli": {
|
||||
"version": ">= 0.52.0"
|
||||
},
|
||||
"build": {
|
||||
"development": {
|
||||
"developmentClient": true,
|
||||
"distribution": "internal"
|
||||
},
|
||||
"preview": {
|
||||
"distribution": "internal"
|
||||
},
|
||||
"production": {}
|
||||
},
|
||||
"submit": {
|
||||
"production": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Builds erstellen
|
||||
|
||||
```bash
|
||||
# Development Build
|
||||
eas build --profile development
|
||||
|
||||
# Production Build
|
||||
eas build --profile production
|
||||
```
|
||||
|
||||
### App Store Submission
|
||||
|
||||
```bash
|
||||
# iOS App Store
|
||||
eas submit --platform ios
|
||||
|
||||
# Google Play Store
|
||||
eas submit --platform android
|
||||
```
|
||||
|
||||
## 6. Monitoring & Maintenance
|
||||
|
||||
### Supabase Dashboard
|
||||
|
||||
- Database Performance
|
||||
- Storage Usage
|
||||
- Edge Function Logs
|
||||
- User Activity
|
||||
|
||||
### Google Cloud Monitoring
|
||||
|
||||
- API Usage
|
||||
- Kosten überwachen
|
||||
- Rate Limits prüfen
|
||||
|
||||
### App Analytics
|
||||
|
||||
- Expo Analytics
|
||||
- Crashlytics Integration
|
||||
- Performance Monitoring
|
||||
|
||||
## 7. Kosten-Optimierung
|
||||
|
||||
### Google Cloud TTS
|
||||
|
||||
- Erste 1M Zeichen/Monat kostenlos
|
||||
- Neural2 Stimmen: $16/1M Zeichen
|
||||
- Caching implementiert zur Kostenreduzierung
|
||||
|
||||
### Supabase
|
||||
|
||||
- Free Tier: 500MB DB, 1GB Storage
|
||||
- Pro Tier: $25/Monat für erweiterte Features
|
||||
- Storage: $0.021/GB/Monat
|
||||
|
||||
## 8. Sicherheit
|
||||
|
||||
### Best Practices
|
||||
|
||||
- API Keys niemals in Client-Code
|
||||
- Row Level Security (RLS) aktiviert
|
||||
- Signed URLs für Audio-Dateien
|
||||
- JWT Token Validation
|
||||
|
||||
### Regelmäßige Updates
|
||||
|
||||
- Dependencies aktualisieren
|
||||
- Sicherheitspatches einspielen
|
||||
- API Key Rotation
|
||||
|
||||
## 9. Troubleshooting
|
||||
|
||||
### Häufige Probleme
|
||||
|
||||
1. **Audio-Generierung fehlschlägt**
|
||||
- Google Cloud API Key prüfen
|
||||
- Quota-Limits prüfen
|
||||
- Edge Function Logs kontrollieren
|
||||
|
||||
2. **Supabase Connection Issues**
|
||||
- Environment Variables prüfen
|
||||
- RLS Policies kontrollieren
|
||||
- Database Connection Pool
|
||||
|
||||
3. **Audio-Wiedergabe Probleme**
|
||||
- Expo AV Permissions
|
||||
- File System Access
|
||||
- Audio Format Kompatibilität
|
||||
|
||||
### Logs & Debugging
|
||||
|
||||
```bash
|
||||
# Supabase Logs
|
||||
supabase logs
|
||||
|
||||
# Edge Function Logs
|
||||
supabase functions logs generate-audio
|
||||
|
||||
# App Logs
|
||||
expo logs
|
||||
```
|
||||
|
||||
## 10. Nächste Schritte
|
||||
|
||||
### Feature Roadmap
|
||||
|
||||
- Push Notifications
|
||||
- Offline-First Synchronisation
|
||||
- Cloud Backup
|
||||
- Multi-User Support
|
||||
- Advanced Audio Controls
|
||||
|
||||
### Performance Optimierung
|
||||
|
||||
- Image Optimization
|
||||
- Bundle Size Reduction
|
||||
- Lazy Loading
|
||||
- Background Processing
|
||||
134
apps-archived/reader/apps/mobile/docs/google-cloud-setup.md
Normal file
134
apps-archived/reader/apps/mobile/docs/google-cloud-setup.md
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
# Google Cloud Text-to-Speech Setup
|
||||
|
||||
## 1. Google Cloud Projekt erstellen
|
||||
|
||||
1. Besuche die [Google Cloud Console](https://console.cloud.google.com/)
|
||||
2. Erstelle ein neues Projekt oder wähle ein existierendes aus
|
||||
3. Notiere dir die **Project ID**
|
||||
|
||||
## 2. Text-to-Speech API aktivieren
|
||||
|
||||
1. Gehe zu "APIs & Services" → "Library"
|
||||
2. Suche nach "Cloud Text-to-Speech API"
|
||||
3. Klicke auf "Enable"
|
||||
|
||||
## 3. Service Account erstellen
|
||||
|
||||
1. Gehe zu "IAM & Admin" → "Service Accounts"
|
||||
2. Klicke auf "Create Service Account"
|
||||
3. Name: `reader-tts-service`
|
||||
4. Rolle: `Cloud Text-to-Speech Client`
|
||||
5. Klicke auf "Create and Continue"
|
||||
|
||||
## 4. API Key erstellen (Alternative)
|
||||
|
||||
Für einfache Implementierung können wir einen API Key verwenden:
|
||||
|
||||
1. Gehe zu "APIs & Services" → "Credentials"
|
||||
2. Klicke auf "Create Credentials" → "API Key"
|
||||
3. Kopiere den API Key
|
||||
4. Klicke auf "Restrict Key" für Sicherheit
|
||||
5. Unter "API restrictions" wähle "Cloud Text-to-Speech API"
|
||||
|
||||
## 5. Supabase Environment Variables
|
||||
|
||||
Füge folgende Variablen in deine Supabase Edge Functions ein:
|
||||
|
||||
```bash
|
||||
# In der Supabase Dashboard unter Settings → Edge Functions → Environment Variables
|
||||
GOOGLE_TTS_API_KEY=dein_api_key_hier
|
||||
```
|
||||
|
||||
## 6. Verfügbare Google Cloud TTS Voices
|
||||
|
||||
### Deutsch (de-DE)
|
||||
|
||||
#### Neural2 Voices (Empfohlen - beste Balance zwischen Qualität und Kosten)
|
||||
|
||||
- `de-DE-Neural2-A` (weiblich)
|
||||
- `de-DE-Neural2-B` (männlich)
|
||||
- `de-DE-Neural2-C` (weiblich)
|
||||
- `de-DE-Neural2-D` (männlich)
|
||||
- `de-DE-Neural2-E` (weiblich)
|
||||
- `de-DE-Neural2-F` (männlich)
|
||||
|
||||
#### WaveNet Voices (Hochqualitativ)
|
||||
|
||||
- `de-DE-Wavenet-A` (weiblich)
|
||||
- `de-DE-Wavenet-B` (männlich)
|
||||
- `de-DE-Wavenet-C` (weiblich)
|
||||
- `de-DE-Wavenet-D` (männlich)
|
||||
- `de-DE-Wavenet-E` (weiblich)
|
||||
- `de-DE-Wavenet-F` (männlich)
|
||||
|
||||
#### Studio Voices (Broadcast-Qualität)
|
||||
|
||||
- `de-DE-Studio-B` (männlich)
|
||||
- `de-DE-Studio-C` (weiblich)
|
||||
|
||||
#### Standard Voices (Basis-Qualität, günstigste Option)
|
||||
|
||||
- `de-DE-Standard-A` (weiblich)
|
||||
- `de-DE-Standard-B` (männlich)
|
||||
- `de-DE-Standard-C` (weiblich)
|
||||
- `de-DE-Standard-D` (männlich)
|
||||
- `de-DE-Standard-E` (weiblich)
|
||||
- `de-DE-Standard-F` (männlich)
|
||||
|
||||
### Englisch (US)
|
||||
|
||||
- `en-US-Neural2-A` (männlich)
|
||||
- `en-US-Neural2-C` (weiblich)
|
||||
- `en-US-Neural2-D` (männlich)
|
||||
- `en-US-Neural2-E` (weiblich)
|
||||
|
||||
### Englisch (UK)
|
||||
|
||||
- `en-GB-Neural2-A` (weiblich)
|
||||
- `en-GB-Neural2-B` (männlich)
|
||||
- `en-GB-Neural2-C` (weiblich)
|
||||
- `en-GB-Neural2-D` (männlich)
|
||||
|
||||
## 7. Kostenschätzung
|
||||
|
||||
- **Standard Voices**: $4.00 pro 1 Million Zeichen
|
||||
- **Neural2 Voices**: $16.00 pro 1 Million Zeichen
|
||||
- **Erstes 1 Million Zeichen pro Monat**: Kostenlos
|
||||
|
||||
### Beispielrechnung für 10.000 Zeichen:
|
||||
|
||||
- Standard: $0.04
|
||||
- Neural2: $0.16
|
||||
|
||||
## 8. Quotas und Limits
|
||||
|
||||
- **Requests pro Minute**: 1,000
|
||||
- **Requests pro Tag**: 100,000
|
||||
- **Zeichen pro Request**: 5,000
|
||||
|
||||
## 9. Test der API
|
||||
|
||||
```bash
|
||||
curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"input": {"text": "Hallo Welt, das ist ein Test."},
|
||||
"voice": {"languageCode": "de-DE", "name": "de-DE-Neural2-A"},
|
||||
"audioConfig": {"audioEncoding": "MP3"}
|
||||
}' \
|
||||
"https://texttospeech.googleapis.com/v1/text:synthesize?key=YOUR_API_KEY"
|
||||
```
|
||||
|
||||
## 10. Nächste Schritte
|
||||
|
||||
1. API Key in Supabase Environment Variables eintragen
|
||||
2. Edge Functions deployen
|
||||
3. Audio-Generierung in der App testen
|
||||
4. Monitoring und Logging einrichten
|
||||
|
||||
## Sicherheitshinweise
|
||||
|
||||
- API Key niemals in Client-Code einbetten
|
||||
- Nur über Supabase Edge Functions verwenden
|
||||
- Regelmäßige Rotation der API Keys
|
||||
- Monitoring der API-Nutzung einrichten
|
||||
149
apps-archived/reader/apps/mobile/docs/url-extraction-options.md
Normal file
149
apps-archived/reader/apps/mobile/docs/url-extraction-options.md
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
# URL-Extraktion Optionen
|
||||
|
||||
## Problem
|
||||
|
||||
Viele Webseiten zeigen Cookie-Banner oder andere Overlays, die den eigentlichen Inhalt blockieren.
|
||||
|
||||
## Lösungsoptionen
|
||||
|
||||
### 1. **ScrapingBee API** (Empfohlen für Production)
|
||||
|
||||
- **Vorteile**:
|
||||
- JavaScript-Rendering
|
||||
- Automatisches Cookie-Banner-Handling
|
||||
- Anti-Bot-Umgehung
|
||||
- Einfache Integration
|
||||
- **Nachteile**:
|
||||
- Kostenpflichtig (1000 kostenlose Credits/Monat)
|
||||
- API-Key erforderlich
|
||||
- **Setup**:
|
||||
1. Account bei [ScrapingBee](https://www.scrapingbee.com) erstellen
|
||||
2. API-Key in Supabase Secrets speichern: `SCRAPINGBEE_API_KEY`
|
||||
3. Edge Function `extract-url-scrapingbee` deployen
|
||||
|
||||
### 2. **Browserless.io**
|
||||
|
||||
- **Vorteile**:
|
||||
- Headless Chrome as a Service
|
||||
- Puppeteer/Playwright kompatibel
|
||||
- Cookie-Banner können programmatisch geklickt werden
|
||||
- **Nachteile**:
|
||||
- Kostenpflichtig
|
||||
- Komplexere Integration
|
||||
- **Code-Beispiel**:
|
||||
|
||||
```typescript
|
||||
const browserlessUrl = `https://chrome.browserless.io/content?token=${BROWSERLESS_TOKEN}`;
|
||||
const response = await fetch(browserlessUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
url: targetUrl,
|
||||
waitFor: 3000,
|
||||
scripts: [
|
||||
{
|
||||
content: `document.querySelectorAll('[class*="cookie"] button').forEach(b => b.click())`,
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
### 3. **Reader API von Jina.ai** (Einfachste Lösung)
|
||||
|
||||
- **Vorteile**:
|
||||
- Kostenlos
|
||||
- Keine Registrierung
|
||||
- Einfache Integration
|
||||
- **Nachteile**:
|
||||
- Weniger Kontrolle
|
||||
- Rate Limits
|
||||
- **Implementierung**:
|
||||
|
||||
```typescript
|
||||
const response = await fetch(`https://r.jina.ai/${encodeURIComponent(url)}`, {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'X-With-Images': 'false',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### 4. **Client-seitige Lösung** (iOS/Android)
|
||||
|
||||
- **iOS**: SFSafariViewController mit Reader Mode
|
||||
- **Android**: Chrome Custom Tabs mit Reader Mode
|
||||
- **React Native**:
|
||||
|
||||
```typescript
|
||||
import { WebView } from 'react-native-webview';
|
||||
|
||||
// Injiziere JavaScript um Content zu extrahieren
|
||||
const injectedJS = `
|
||||
// Entferne Cookie-Banner
|
||||
document.querySelectorAll('[class*="cookie"]').forEach(el => el.remove());
|
||||
// Sende Content zurück
|
||||
window.ReactNativeWebView.postMessage(document.body.innerText);
|
||||
`;
|
||||
```
|
||||
|
||||
### 5. **Proxy-Service mit Playwright**
|
||||
|
||||
Eigener Service auf Vercel/Railway:
|
||||
|
||||
```typescript
|
||||
// api/extract.ts
|
||||
import { chromium } from 'playwright';
|
||||
|
||||
export default async function handler(req, res) {
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage();
|
||||
|
||||
await page.goto(req.query.url);
|
||||
|
||||
// Warte auf Content und klicke Cookie-Banner weg
|
||||
await page.waitForTimeout(2000);
|
||||
await page.click('text=/akzeptieren|accept|agree/i').catch(() => {});
|
||||
|
||||
const content = await page.evaluate(() => {
|
||||
return (
|
||||
document.querySelector('article')?.innerText ||
|
||||
document.querySelector('main')?.innerText ||
|
||||
document.body.innerText
|
||||
);
|
||||
});
|
||||
|
||||
await browser.close();
|
||||
res.json({ content });
|
||||
}
|
||||
```
|
||||
|
||||
## Empfehlung
|
||||
|
||||
Für schnelle Lösung: **Jina.ai Reader API** einbauen
|
||||
Für Production: **ScrapingBee** mit Fallback auf direkte Extraktion
|
||||
|
||||
### Quick Implementation mit Jina.ai:
|
||||
|
||||
```typescript
|
||||
// In extract-url Edge Function
|
||||
try {
|
||||
// Versuche zuerst Jina.ai
|
||||
const jinaResponse = await fetch(`https://r.jina.ai/${url}`, {
|
||||
headers: { Accept: 'application/json' },
|
||||
});
|
||||
|
||||
if (jinaResponse.ok) {
|
||||
const data = await jinaResponse.json();
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
title: data.title,
|
||||
content: data.content,
|
||||
// ... weitere Felder
|
||||
})
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
// Fallback auf normale Extraktion
|
||||
}
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue