holy shit we did it 🅱️ois, we made some progress on improving manual player detection

This commit is contained in:
Tamius Han 2022-06-10 00:22:06 +02:00
parent a1bfaaaf92
commit 320d35d9e5
4 changed files with 171 additions and 25 deletions

View File

@ -86,6 +86,9 @@
></VideoSettings> ></VideoSettings>
<PlayerDetectionPanel <PlayerDetectionPanel
v-if="selectedTab === 'playerDetection'" v-if="selectedTab === 'playerDetection'"
:settings="settings"
:eventBus="eventBus"
:site="site"
> >
</PlayerDetectionPanel> </PlayerDetectionPanel>
<!-- <ResizerDebugPanel :debugData="debugData"> <!-- <ResizerDebugPanel :debugData="debugData">
@ -188,6 +191,8 @@ export default {
}, },
async created() { async created() {
console.log('player-tree: player UI base created')
this.logger = new Logger(); this.logger = new Logger();
await this.logger.init({ await this.logger.init({
allowLogging: true, allowLogging: true,
@ -291,7 +296,7 @@ export default {
selectTab(tab) { selectTab(tab) {
console.log('selected tab:', tab); console.log('selected tab:', tab);
console.warn('NOTE: tab selection is not syet inplemented!') console.warn('NOTE: tab selection is not syet inplemented!');
this.selectedTab = tab; this.selectedTab = tab;
} }
} }

View File

@ -16,6 +16,19 @@
You're probably on this page because Ultrawidify doesn't crop the player correctly. If you want to know more about You're probably on this page because Ultrawidify doesn't crop the player correctly. If you want to know more about
why this happens, explanation can be found on <a href="https://github.com/tamius-han/ultrawidify/wiki/2.-Player-detection-(and-related-problems)#why-does-ultrawidify-have-this-problem-when-this-other-extension-doesnt" target="_blank">the wiki page</a>. why this happens, explanation can be found on <a href="https://github.com/tamius-han/ultrawidify/wiki/2.-Player-detection-(and-related-problems)#why-does-ultrawidify-have-this-problem-when-this-other-extension-doesnt" target="_blank">the wiki page</a>.
</p> </p>
<p>
If you hover over the boxes below, the corresponding element will change (sepia filter + higher brightness + reduced contrast + it gets an outline). Player element
should be the closest element to the video element, for which the sepia/brightness effect covers the area you expect the video will cover.
</p>
<div>
<b>Symbols:</b><br />
<mdicon name="alert-remove" class="invalid" /> Element of invalid dimensions<br />
<mdicon name="refresh-auto" class="auto-match" /> Ultrawidify's player detection thinks this should be the player<br />
<mdicon name="bookmark" class="parent-offset-match" /> Site settings say this should be the player (based on counting parents)<br />
<mdicon name="crosshairs" class="qs-match" /> Site settings say this should be the player (based on query selectors)<br />
<mdicon name="check-circle" class="activePlayer" /> Element that is actually the player
</div>
<div class="element-tree"> <div class="element-tree">
<div class="html-element-boxes"> <div class="html-element-boxes">
@ -25,19 +38,52 @@
class="element-row" class="element-row"
> >
<div class="status"> <div class="status">
<div
v-if="element.heuristics?.invalidSize"
class="invalid"
>
<mdicon name="alert-remove" />
</div>
<div
v-if="element.heuristics?.autoMatch"
class="auto-match"
>
<mdicon name="refresh-auto" />
</div>
<div
v-if="element.heuristics?.qsMatch"
class="qs-match"
>
<mdicon name="crosshairs" />
</div>
<div
v-if="element.heuristics?.manualElementByParentIndex"
class="parent-offset-match"
>
<mdicon name="bookmark" />
</div>
<div
v-if="element.heuristics?.activePlayer"
class="activePlayer"
>
<mdicon name="check-circle" />
</div>
</div> </div>
<div class="element-data"> <div
class="element-data"
@mouseover="markElement(index, true)"
@mouseleave="markElement(index, false)"
>
<div class="tag"> <div class="tag">
{{element.tagName}} <b>{{element.tagName}}</b> <i class="id">{{element.id ? `#`:''}}{{element.id}}</i> @ <span class="dimensions">{{element.width}}</span>x<span class="dimensions">{{element.height}}</span>
</div> </div>
<div v-if="element.id" class="id"> <div v-if="element.classList" class="class-list">
{{element.id}} <div v-for="cls of element.classList" :key="cls">
</div> {{cls}}
<div v-if="element.classList" id="class-list"> </div>
{{element.classList}}
</div>
<div class="dimensions">
{{element.width}} x {{element.height}}
</div> </div>
</div> </div>
<div class="css-fixes"> <div class="css-fixes">
@ -75,17 +121,78 @@ export default({
'site' 'site'
], ],
created() { created() {
this.eventBus.subscribe('uw-player-tree', {function: (elementStack) => this.handleElementStack(elementStack)}); this.eventBus.subscribe('uw-config-broadcast', {function: (config) => this.handleElementStack(config)});
}, },
mounted() { mounted() {
this.eventBus.sendToTunnel('get-player-tree'); // TODO: implement this in PlayerData this.eventBus.sendToTunnel('get-player-tree'); // TODO: implement this in PlayerData
}, },
computed: {}, computed: {},
methods: { methods: {
handleElementStack(elementStack) { handleElementStack(configBroadcast) {
this.elementStack = elementStack; if (configBroadcast.type === 'player-tree') {
this.$nextTick( () => this.$forceUpdate() ); this.elementStack = configBroadcast.config;
this.$nextTick( () => this.$forceUpdate() );
}
},
markElement(parentIndex, enable) {
console.log('will mark element:', parentIndex, enable);
this.eventBus.sendToTunnel('set-mark-element', {parentIndex, enable});
} }
} }
}) })
</script> </script>
<style lang="scss" scoped>
.element-tree {
.html-element-boxes {
display: flex;
flex-direction: column;
.element-row {
display: flex;
flex-direction: row;
margin: 0.5rem;
.status {
width: 6.9rem;
margin-right: 1rem;
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
.invalid {
color: #f00;
}
}
.element-data {
border: 1px solid rgba(255,255,255,0.5);
padding: 0.5rem 1rem;
display: flex;
flex-direction: column;
.tag {
text-transform: lowercase;
font-weight: bold;
}
.id {
font-style: italic;
}
.class-list {
font-style: italic;
opacity: 0.75;
font-size: 0.75rem;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.dimensions {
color: #473c85;
}
}
}
}
}
</style>

View File

@ -96,6 +96,9 @@ class PlayerData {
this.invalid = false; this.invalid = false;
this.element = this.getPlayer(); this.element = this.getPlayer();
this.eventBus.subscribe('get-player-tree', {function: () => this.handlePlayerTreeRequest()});
this.eventBus.subscribe('set-mark-element', {function: (data) => this.markElement(data)});
// this.notificationService = new PlayerNotificationUi(this.element, this.settings, this.eventBus); // this.notificationService = new PlayerNotificationUi(this.element, this.settings, this.eventBus);
this.ui = new UI('ultrawidifyUi', {parentElement: this.element, eventBus: this.eventBus}); this.ui = new UI('ultrawidifyUi', {parentElement: this.element, eventBus: this.eventBus});
// this.ui.init(); // this.ui.init();
@ -413,6 +416,10 @@ class PlayerData {
} }
return false; return false;
} }
equalish(a,b, tolerance) {
return a > b - tolerance && a < b + tolerance;
}
//#endregion //#endregion
/** /**
@ -427,7 +434,10 @@ class PlayerData {
const elementStack: any[] = [{ const elementStack: any[] = [{
element: this.video, element: this.video,
type: 'video' type: 'video',
tagName: 'video',
classList: this.video.classList,
id: this.video.id,
}]; }];
// first pass to generate the element stack and translate it into array // first pass to generate the element stack and translate it into array
@ -456,7 +466,7 @@ class PlayerData {
// if 'verbose' option is passed, we also populate the elementStack // if 'verbose' option is passed, we also populate the elementStack
// with heuristics data for auto player detection. // with heuristics data for auto player detection.
if (playerCandidate && !options?.verbose) { if (playerCandidate && !options?.verbose) {
return playerCandidate; return playerCandidate.element;
} }
} }
@ -464,9 +474,12 @@ class PlayerData {
// remember — we're only populating elementStack. If we found a player // remember — we're only populating elementStack. If we found a player
// element using manual methods, we will still return that element. // element using manual methods, we will still return that element.
this.getPlayerAuto(elementStack, videoWidth, videoHeight); this.getPlayerAuto(elementStack, videoWidth, videoHeight);
return playerCandidate; playerCandidate.heuristics['activePlayer'] = true;
return playerCandidate.element;
} else { } else {
return this.getPlayerAuto(elementStack, videoWidth, videoHeight); const playerCandidate = this.getPlayerAuto(elementStack, videoWidth, videoHeight);
playerCandidate.heuristics['activePlayer'] = true;
return playerCandidate.element;
} }
} }
@ -545,7 +558,7 @@ class PlayerData {
if (bestCandidate.initialValue) { if (bestCandidate.initialValue) {
bestCandidate = null; bestCandidate = null;
} else { } else {
bestCandidate = bestCandidate.element; bestCandidate.heuristics['autoMatch'] = true;
} }
return bestCandidate; return bestCandidate;
@ -587,7 +600,7 @@ class PlayerData {
if (bestCandidate.initialValue) { if (bestCandidate.initialValue) {
bestCandidate = null; bestCandidate = null;
} else { } else {
bestCandidate = bestCandidate.element; bestCandidate.heuristics['qsMatch'] = true;
} }
return bestCandidate; return bestCandidate;
@ -596,11 +609,21 @@ class PlayerData {
private getPlayerParentIndex(elementStack: any[]) { private getPlayerParentIndex(elementStack: any[]) {
const host = window.location.hostname; const host = window.location.hostname;
elementStack[this.settings.active.sites[host].DOM.player.videoAncestor].heuristics['manualElementByParentIndex'] = true; elementStack[this.settings.active.sites[host].DOM.player.videoAncestor].heuristics['manualElementByParentIndex'] = true;
return elementStack[this.settings.active.sites[host].DOM.player.videoAncestor].element; return elementStack[this.settings.active.sites[host].DOM.player.videoAncestor];
} }
equalish(a,b, tolerance) { private handlePlayerTreeRequest() {
return a > b - tolerance && a < b + tolerance; // this populates this.elementStack fully
this.getPlayer({verbose: true});
console.info('player-tree: emitting stack:', this.elementStack);
this.eventBus.send('uw-config-broadcast', {type: 'player-tree', config: JSON.parse(JSON.stringify(this.elementStack))});
}
private markElement(data: {parentIndex: number, enable: boolean}) {
console.log('mark element: got request to do border around this:', data);
this.elementStack[data.parentIndex].element.style.outline = data.enable ? '5px dashed #fa6' : null;
this.elementStack[data.parentIndex].element.style.filter = data.enable ? 'sepia(1) brightness(2) contrast(0.5)' : null;
} }
forceRefreshPlayerElement() { forceRefreshPlayerElement() {

View File

@ -94,6 +94,7 @@ class VideoData {
this.eventBus.setUpstreamBus(pageInfo.eventBus); this.eventBus.setUpstreamBus(pageInfo.eventBus);
} }
this.setupStageOne(); this.setupStageOne();
} }
@ -618,7 +619,7 @@ class VideoData {
return heightCompensationFactor; return heightCompensationFactor;
} }
//#region AARD handlers //#region AARD handlers — TODO: remove, AARD handlers shouldn't be here
initArDetection() { initArDetection() {
if(this.destroyed || this.invalid) { if(this.destroyed || this.invalid) {
// throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}}; // throw {error: 'VIDEO_DATA_DESTROYED', data: {videoData: this}};
@ -748,6 +749,16 @@ class VideoData {
return false; return false;
} }
/**
* Returns:
* * number of parent elements on route from <video> to <body>
* * parent index of automatically detected player element
* * index of current player element
*/
getPageOutline() {
}
} }
export default VideoData; export default VideoData;