Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion plugins/AIOverhaul/AIOverhaul.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: AIOverhaul
description: AI Overhaul for Stash with a full plugin engine included to install and manage asynchronous stash plugins for AI or other purposes.
version: 0.9.1
version: 0.9.2
url: https://discourse.stashapp.cc/t/aioverhaul/4847
ui:
javascript:
Expand All @@ -26,6 +26,9 @@ ui:
- http://localhost:4153
- ws://localhost:4153
- https://localhost:4153
- http://127.0.0.1:4153
- ws://127.0.0.1:4153
- https://127.0.0.1:4153
# Add additional urls here for the stash-ai-server if your browser is not on the same host
interface: raw
exec:
Expand Down
43 changes: 34 additions & 9 deletions plugins/AIOverhaul/InteractionTracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -817,8 +817,18 @@ class InteractionTracker {
handlePageContext(ctx) {
if (!ctx)
return;
if (!ctx.isDetailView || !ctx.entityId)
// When leaving detail views, allow future entries (even same entity) to re-fire
if (!ctx.isDetailView || !ctx.entityId) {
this.lastDetailKey = null;
// Clear scene context so subsequent scene visits don't reuse stale ids
this.lastScenePageEntered = null;
if (this.currentScene) {
this.cleanupVideoElement(this.currentScene.video);
this.detachVideoJsWatcher(this.currentScene);
this.currentScene = undefined;
}
return;
}
const key = ctx.page + ':' + ctx.entityId;
if (key === this.lastDetailKey)
return;
Expand Down Expand Up @@ -1248,12 +1258,14 @@ class InteractionTracker {
const delay = attempt === 0 ? 0 : Math.min(600, 80 + attempt * 80);
const handle = window.setTimeout(() => {
this.playerReinstrumentTimers.delete(player);
const success = this.instrumentSceneWithVideoJs(sceneId, { player, attempt });
const targetSceneId = this.resolveSceneIdFromContext() || sceneId;
// If navigation switched scenes, avoid applying the old scene id
const success = this.instrumentSceneWithVideoJs(targetSceneId, { player, attempt });
if (success) {
this.pendingVideoJsPlayers.delete(player);
}
else if (attempt < 6) {
this.queuePlayerReinstrument(sceneId, player, attempt + 1);
this.queuePlayerReinstrument(targetSceneId, player, attempt + 1);
}
}, delay);
this.playerReinstrumentTimers.set(player, handle);
Expand Down Expand Up @@ -1354,17 +1366,24 @@ class InteractionTracker {
}
this.currentScene = state;
this.cleanupVideoElement(video);
const onPlay = () => {
const beginPlayback = () => {
var _a, _b, _c, _d;
if (state.lastPlayTs != null)
return; // already marked playing
const snapshot = this.getPlaybackSnapshot(state);
state.lastPlayTs = Date.now();
// If we attached mid-autoplay with no segments yet, backfill start time from current position
const now = Date.now();
const backfill = snapshot.position !== undefined && snapshot.position > 0.5 && state.segments.length === 0;
state.lastPlayTs = backfill ? now - snapshot.position * 1000 : now;
if (snapshot.position !== undefined)
state.lastPosition = snapshot.position;
this.trackInternal('scene_watch_start', 'scene', sceneId, {
position: (_b = (_a = snapshot.position) !== null && _a !== void 0 ? _a : state.lastPosition) !== null && _b !== void 0 ? _b : (isFinite(video.currentTime) ? video.currentTime : undefined),
duration: (_d = (_c = snapshot.duration) !== null && _c !== void 0 ? _c : state.duration) !== null && _d !== void 0 ? _d : (isFinite(video.duration) ? video.duration : undefined)
});
};
const onPlay = () => { beginPlayback(); };
const onPlaying = () => { beginPlayback(); };
const onPause = () => {
var _a, _b, _c, _d;
const added = this.captureSegment();
Expand Down Expand Up @@ -1416,24 +1435,30 @@ class InteractionTracker {
state.duration = video.duration;
};
video.addEventListener('play', onPlay);
video.addEventListener('playing', onPlaying);
video.addEventListener('pause', onPause);
video.addEventListener('ended', onEnded);
video.addEventListener('timeupdate', onTimeUpdate);
video.addEventListener('loadedmetadata', onLoaded);
video._aiInteractionCleanup = () => {
video.removeEventListener('play', onPlay);
video.removeEventListener('playing', onPlaying);
video.removeEventListener('pause', onPause);
video.removeEventListener('ended', onEnded);
video.removeEventListener('timeupdate', onTimeUpdate);
video.removeEventListener('loadedmetadata', onLoaded);
};
if (state.player)
this.attachVideoJsWatcher(state, sceneId, state.player);
const triggerIfAlreadyPlaying = () => {
if (!video.isConnected)
return;
if (!video.paused || (isFinite(video.currentTime) && video.currentTime > 0))
beginPlayback();
};
triggerIfAlreadyPlaying();
if (!video.paused) {
setTimeout(() => {
if (video.isConnected && !video.paused)
onPlay();
}, 0);
setTimeout(() => { triggerIfAlreadyPlaying(); }, 0);
}
}
trackImageView(imageId, opts) {
Expand Down