Compare commits
No commits in common. "2f68b118c65876dd276c1c5a40ba819f472da398" and "19483c026bdfedf94e8aa30b1737e3c987c1063c" have entirely different histories.
2f68b118c6
...
19483c026b
8 changed files with 13 additions and 138 deletions
|
|
@ -221,12 +221,6 @@ def _coalesce_canonical_fields(keep: Scene, drop: Scene) -> None:
|
|||
if drop.title and len(drop.title) > len(keep.title or ""):
|
||||
keep.title = drop.title
|
||||
keep.title_normalized = drop.title_normalized
|
||||
# created_at = najwcześniejsze "first seen" obu scen. NEW badge (apka) bazuje na
|
||||
# created_at; gdy dedup wybierze świeży re-ingest/mirror jako `keep`, stara treść
|
||||
# dostawałaby fałszywe NEW po merdżu (report f17799b3). Bierzemy min → zdeduplikowana
|
||||
# scena zachowuje datę pierwszego pojawienia, nie datę re-ingestu.
|
||||
if drop.created_at and keep.created_at and drop.created_at < keep.created_at:
|
||||
keep.created_at = drop.created_at
|
||||
|
||||
|
||||
def _close_pending_candidates(
|
||||
|
|
|
|||
|
|
@ -39,13 +39,6 @@ _PAGE_CAP: dict[str, int] = {
|
|||
"xvideoscom": 1800,
|
||||
}
|
||||
|
||||
# Miękki budżet czasu na run (s). Detail-fetch scrapery (per-scena fetch strony, np.
|
||||
# przez wolne proxy) potrafią przekroczyć hard-timeout 3600s z _job_deep_crawl → run
|
||||
# ubijany w locie, kursor NIE zapisany (orphan thread), tube zero postępu + alert
|
||||
# GOON-V. Budżet < hard-timeout: przerywamy PO skończonej stronie, zapisujemy kursor,
|
||||
# wracamy czysto — następny run kontynuuje. Margines 600s na dokończenie strony w toku.
|
||||
_RUN_BUDGET_SEC = 3000
|
||||
|
||||
|
||||
def _state_path() -> Path:
|
||||
return Path(getattr(get_settings(), "deepcrawl_state_path", None) or _DEFAULT_STATE)
|
||||
|
|
@ -126,7 +119,6 @@ def run_deep_crawl(*, pages_per_run: int = 60, sitetags: list[str] | None = None
|
|||
t0 = time.time()
|
||||
last_done = start - 1
|
||||
exhausted = False
|
||||
budget_hit = False
|
||||
|
||||
if cap is not None and start > cap:
|
||||
# kursor osiągnął per-tube cap → traktuj jak koniec katalogu (reset re-sweepuje od 1)
|
||||
|
|
@ -149,17 +141,7 @@ def run_deep_crawl(*, pages_per_run: int = 60, sitetags: list[str] | None = None
|
|||
except Exception:
|
||||
counters["errors"] += 1
|
||||
last_done = page
|
||||
# Miękki budżet: stop po skończonej stronie (kursor=last_done zapisany niżej),
|
||||
# zanim hard-timeout ubije run mid-page (orphan thread, kursor zgubiony — GOON-V).
|
||||
if time.time() - t0 > _RUN_BUDGET_SEC:
|
||||
budget_hit = True
|
||||
log.warning(
|
||||
"deep-crawl %s: run budget %ds hit at page %d (%d/%d stron) — stop czysto, "
|
||||
"kursor zapisany, kontynuacja w następnym runie",
|
||||
sitetag, _RUN_BUDGET_SEC, page, page - start + 1, pages_per_run,
|
||||
)
|
||||
break
|
||||
if not budget_hit and cap is not None and last_done >= cap:
|
||||
if cap is not None and last_done >= cap:
|
||||
log.info("deep-crawl %s: reached page cap %d (exhausted)", sitetag, cap)
|
||||
exhausted = True
|
||||
|
||||
|
|
@ -170,10 +152,7 @@ def run_deep_crawl(*, pages_per_run: int = 60, sitetags: list[str] | None = None
|
|||
_save_state(state)
|
||||
|
||||
log.info(
|
||||
"deep-crawl %s pages %d-%d: %s exhausted=%s budget_hit=%s (%.0fs)",
|
||||
sitetag, start, last_done, counters, exhausted, budget_hit, time.time() - t0,
|
||||
"deep-crawl %s pages %d-%d: %s exhausted=%s (%.0fs)",
|
||||
sitetag, start, last_done, counters, exhausted, time.time() - t0,
|
||||
)
|
||||
return {
|
||||
"sitetag": sitetag, "start": start, "end": last_done,
|
||||
"exhausted": exhausted, "budget_hit": budget_hit, **counters,
|
||||
}
|
||||
return {"sitetag": sitetag, "start": start, "end": last_done, "exhausted": exhausted, **counters}
|
||||
|
|
|
|||
|
|
@ -26,12 +26,7 @@ from app.db import session_scope
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
_TELEMETRY_WINDOW_DAYS = 7
|
||||
# Poniżej tego telemetria niemiarodajna → proxy. Próg podniesiony 10→25 (2026-06-29):
|
||||
# freshporno (5★ fresh+rich, realnie gra — zweryfikowane 206/507MB) dostało health=0 →
|
||||
# "OFFLINE" na podstawie 10 prób z jednego pechowego okna (CDN-node blip), user-report
|
||||
# cb526949. 25 prób to sensowniejszy próg pewności zanim ogłosimy źródło offline; przy
|
||||
# mniejszej próbce lecimy na proxy/heurystykę (nie zerujemy gwiazdek znanemu-dobremu).
|
||||
_TELEMETRY_MIN_ATTEMPTS = 25
|
||||
_TELEMETRY_MIN_ATTEMPTS = 10 # poniżej tego telemetria niemiarodajna → proxy
|
||||
_EVENT_RETENTION_DAYS = 30
|
||||
# Richness: wagi składowych (suma=1.0). thumb to minimum higieny, canonical-bogactwo
|
||||
# (desc/studio/tag/perf) waży więcej. dur średnio.
|
||||
|
|
|
|||
|
|
@ -16,21 +16,6 @@ export type ChangelogEntry = {
|
|||
};
|
||||
|
||||
export const CHANGELOG: ChangelogEntry[] = [
|
||||
{
|
||||
id: '2026-06-29b',
|
||||
date: 'June 2026',
|
||||
items: [
|
||||
'Seeking (swipe or drag) no longer pops a big pause button into the middle of the screen.',
|
||||
'Diagnostics "open in browser" now opens privately inside the app (incognito) — no cookies, no trace in your real browser.',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '2026-06-29',
|
||||
date: 'June 2026',
|
||||
items: [
|
||||
'No more brief blast of sound when a video page is opening — it stays muted until you tap.',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '2026-06-26',
|
||||
date: 'June 2026',
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import React from 'react';
|
|||
import { Pressable, Text, View } from 'react-native';
|
||||
import { AppLockSettingsScreen } from './screens/AppLockSettingsScreen';
|
||||
import { BlacklistScreen } from './screens/BlacklistScreen';
|
||||
import { DiagnosticBrowserScreen } from './screens/DiagnosticBrowserScreen';
|
||||
import { DonateScreen } from './screens/DonateScreen';
|
||||
import { FavoritesScreen } from './screens/FavoritesScreen';
|
||||
import { MovieDetailScreen } from './screens/MovieDetailScreen';
|
||||
|
|
@ -53,8 +52,6 @@ export type RootStackParamList = {
|
|||
AppLockSettings: undefined;
|
||||
Blacklist: undefined;
|
||||
Donate: undefined;
|
||||
// In-app incognito browser do diagnostyki hostera (long-press na linku playbacku).
|
||||
DiagnosticBrowser: { url: string };
|
||||
Player: {
|
||||
url: string;
|
||||
sceneId: string;
|
||||
|
|
@ -278,11 +275,6 @@ export function AppNavigator({ onLogout, client, appVersion }: AppNavigatorProps
|
|||
component={DonateScreen}
|
||||
options={{ title: 'Support project' }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="DiagnosticBrowser"
|
||||
component={DiagnosticBrowserScreen}
|
||||
options={{ title: 'Diagnostics (incognito)' }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Player"
|
||||
component={PlayerScreen}
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
import { useRoute, type RouteProp } from '@react-navigation/native';
|
||||
import React from 'react';
|
||||
import { ActivityIndicator, StyleSheet, View } from 'react-native';
|
||||
import { WebView } from 'react-native-webview';
|
||||
import type { RootStackParamList } from '../navigation';
|
||||
import { theme } from '../theme';
|
||||
|
||||
// Diagnostyczny in-app browser w trybie incognito (report dccc05e4). Long-press na
|
||||
// linku playbacku → "Open in browser (diagnostics)" otwiera page_url hostera tutaj,
|
||||
// żeby user ocenił czy faktycznie broken. `incognito` → zero cookies/cache/historii:
|
||||
// świeży widok strony (jak u kogoś bez sesji) ORAZ nie zostawia NSFW URL-a w prawdziwej
|
||||
// przeglądarce usera. Wcześniej Linking.openURL wrzucał to do Chrome z jego sesją.
|
||||
export function DiagnosticBrowserScreen() {
|
||||
const route = useRoute<RouteProp<RootStackParamList, 'DiagnosticBrowser'>>();
|
||||
const { url } = route.params;
|
||||
return (
|
||||
<View style={styles.root}>
|
||||
<WebView
|
||||
source={{ uri: url }}
|
||||
incognito
|
||||
cacheEnabled={false}
|
||||
thirdPartyCookiesEnabled={false}
|
||||
startInLoadingState
|
||||
renderLoading={() => (
|
||||
<View style={styles.loading}>
|
||||
<ActivityIndicator color={theme.fg} size="large" />
|
||||
</View>
|
||||
)}
|
||||
style={styles.web}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: { flex: 1, backgroundColor: theme.bg },
|
||||
web: { flex: 1, backgroundColor: theme.bg },
|
||||
loading: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: theme.bg,
|
||||
},
|
||||
});
|
||||
|
|
@ -575,9 +575,7 @@ function NativeVideoPlayer({ params }: { params: RouteParams }) {
|
|||
.onStart(() => {
|
||||
cancelHide();
|
||||
panStartTimeRef.current = player.currentTime || 0;
|
||||
// NIE pokazujemy pełnych kontrolek przy swipe-seeku — pan ma własny popup
|
||||
// ±czas (panSeekBubble). Wcześniej setControlsVisible(true) wyrzucał duży
|
||||
// przycisk pauzy na środek i zostawiał go ~3.5s po puszczeniu (report dccc05e4).
|
||||
setControlsVisible(true);
|
||||
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light).catch(() => {});
|
||||
})
|
||||
.onUpdate((e) => {
|
||||
|
|
@ -688,9 +686,6 @@ function NativeVideoPlayer({ params }: { params: RouteParams }) {
|
|||
// Priorytet: scrubber (palec na pasku) > pan-seek (swipe na video) > playback.
|
||||
const panSeekRatio = panSeekTarget !== null && dur > 0 ? panSeekTarget / dur : null;
|
||||
const displayRatio = scrubbingRatio ?? panSeekRatio ?? progressRatio;
|
||||
// Aktywne przewijanie (palec na pasku albo swipe) — chowamy wtedy duży środkowy
|
||||
// przycisk play/pauza (report dccc05e4): przy seeku nie chcesz wielkiej pauzy na ekranie.
|
||||
const isSeeking = panSeekTarget !== null || scrubX !== null;
|
||||
const displayedTime =
|
||||
scrubbingRatio !== null
|
||||
? scrubbingRatio * dur
|
||||
|
|
@ -780,13 +775,11 @@ function NativeVideoPlayer({ params }: { params: RouteParams }) {
|
|||
</Pressable>
|
||||
</View>
|
||||
|
||||
{!isSeeking && (
|
||||
<View style={styles.controlsCenter} pointerEvents="box-none">
|
||||
<Pressable onPress={togglePlay} hitSlop={20} style={styles.playBtn}>
|
||||
<Text style={styles.playBtnText}>{isPlaying ? '❚❚' : '▶'}</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
)}
|
||||
<View style={styles.controlsCenter} pointerEvents="box-none">
|
||||
<Pressable onPress={togglePlay} hitSlop={20} style={styles.playBtn}>
|
||||
<Text style={styles.playBtnText}>{isPlaying ? '❚❚' : '▶'}</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
<View style={styles.controlsBottom} pointerEvents="box-none">
|
||||
<Text style={styles.timeText}>{formatTime(displayedTime)}</Text>
|
||||
|
|
@ -879,22 +872,6 @@ const INJECTED_JS = `
|
|||
if (window.__goonPatched) return;
|
||||
window.__goonPatched = true;
|
||||
|
||||
// -- 0a. Mute autoplay until the FIRST user gesture (kills the brief unmuted-audio
|
||||
// flash gdy WebView otwiera stronę żeby przechwycić stream — report dccc05e4).
|
||||
// Override play() PRZED page JS: bez gestu → muted; po tapie usera → dźwięk
|
||||
// dozwolony (zgodne z "dźwięk dopiero po geście usera"). Element-level mute
|
||||
// niżej łapał za późno (autoplay z dźwiękiem zdążył ruszyć).
|
||||
try {
|
||||
var _goonOrigPlay = HTMLMediaElement.prototype.play;
|
||||
HTMLMediaElement.prototype.play = function() {
|
||||
if (!window.__goonUserGestured) { try { this.muted = true; } catch (e) {} }
|
||||
return _goonOrigPlay.apply(this, arguments);
|
||||
};
|
||||
var _goonAllowSound = function() { window.__goonUserGestured = true; };
|
||||
window.addEventListener('touchstart', _goonAllowSound, { once: true, capture: true });
|
||||
window.addEventListener('click', _goonAllowSound, { once: true, capture: true });
|
||||
} catch (e) {}
|
||||
|
||||
// -- 0. Anti-adblock detection bypass --------------------------------------
|
||||
// Hostery sprawdzają czy ad-script się załadował (np. /js/dnsads.js ustawia
|
||||
// \`window.cRAds\`). Blokujemy te requesty na poziomie AD_HOSTS, więc flag
|
||||
|
|
|
|||
|
|
@ -775,15 +775,12 @@ function PlaybackButton({
|
|||
'What do you want to do with this link?',
|
||||
[
|
||||
{
|
||||
text: 'Open in browser (incognito)',
|
||||
text: 'Open in browser (diagnostics)',
|
||||
onPress: async () => {
|
||||
try {
|
||||
const url = source.page_url || source.embed_url || source.stream_url;
|
||||
if (url) {
|
||||
// In-app incognito WebView (report dccc05e4): świeży widok bez sesji/
|
||||
// cookies usera i bez śladu w prawdziwej przeglądarce. Zamiast
|
||||
// Linking.openURL (otwierał Chrome z historią + sesją).
|
||||
nav.navigate('DiagnosticBrowser', { url });
|
||||
await Linking.openURL(url);
|
||||
} else {
|
||||
Alert.alert('No URL', 'This playback has no page_url to open.');
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue