Welcome Guest ( Log In | Register )

8 Pages V < 1 2 3 4 5 > »   
Reply to this topicStart new topic
> Userscript index, For non-HV scripts

 
post May 26 2019, 20:42
Post #41
Someguywith



Astolfo~
*********
Group: Gold Star Club
Posts: 7,427
Joined: 27-September 15
Level 397 (Godslayer)


I didn't like that you can't bump a gallary with one button

Current implementation is kinda hacky seeing as it just sets a value and then presses submit for you. I tried getting a html post to work but it kept changing my post data for some reason.

**edit** Managed to find out why it wasn't working as I intended it. Combination of sending it as pain text instead of encoded and the fact that document.url was a string instead of a variable. Thanks to Shapes, Flarpa and Blue Penguin <3

CODE
// ==UserScript==
// @name            Sort Bounties By Reward
// @description     Sort bounties by reward
// @include         https://e-hentai.org/bounty.php*
// @exclude         https://e-hentai.org/bounty.php?bid=*
// @version         1.0
// @namespace       SomeGuyWith, https://forums.e-hentai.org/index.php?showuser=2725435
// ==/UserScript==
(function() {

/*** Settings ***/
var hathToCredits = 4032
var credits = 5000
var hath = 0
/*** End of Settings ***/

var i = 0
var table = document.getElementsByClassName('itg');
var rows = table[0].rows;
var main = document.getElementById('s');
var method = "POST";
var postData = "grant_cred=" + credits + "&grant_hath=" + hath + "&addreward=Submit+Additional+Reward";
var shouldBeAsync = true;
var request = new XMLHttpRequest();

// fix css
main.style.width = '1330px';
table[0].style.maxWidth = '99%';

for (let row of rows) {
  if (row === rows[0]) {
    var head = row.insertCell(5);
    head.innerHTML = 'Quick Bump'
    head.style.backgroundColor = '#E0DED3'
    head.style.fontWeight = 'bold';
    head.style.padding = '3px 4px';
    head.style.height = '16px';
  } else {
    var cell = row.insertCell(5);
    var button = document.createElement('input');
    cell.innerHTML = '<input type="button" name="addreward" value="QB (C: ' + credits + ' H: ' + hath + ')" id="quickBump" style="width: 130px; line-height: 10px; min-height: 10px; padding-top: 2px">';
    cell.style.width = '135px';
    cell.addEventListener(
      "click", onClick, false
    );
  }
}

const comparer = (idx, asc) => (a, b) => ((v1, v2) =>
  v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2)
)(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));

document.querySelectorAll('th').forEach(th => th.addEventListener('click', (() => {
  const table = th.closest('table');
  Array.from(table.querySelectorAll('tr:nth-child(n+2)'))
    .sort(comparer(Array.from(th.parentNode.children).indexOf(th), this.asc = !this.asc))
    .forEach(tr => table.appendChild(tr));
})));

function getNumerical(txt) {
  var credits = txt.match(/([0-9, ]+)Credits/i);
  var hath = txt.match(/([0-9, ]+)Hath/i);
  var reward = 0;
  if (credits) {
    credits = parseInt(credits[1].replace(/[, ]/g, ''))
    reward += credits
  }
  if (hath) {
    hath = parseInt(hath[1].replace(/[, ]/g, ''))
    reward += (hath * hathToCredits)
  }
  return reward
}

const getCellValue = (tr, idx) => {
  if (idx === 4) {
    return getNumerical(tr.children[idx].innerText)
  } else {
    return tr.children[idx].innerText || tr.children[idx].textContent;
  }
}

function onClick(elem) {
  console.log(elem.path[2].cells[1].children[0].href)
  request.open(method, elem.path[2].cells[1].children[0].href, shouldBeAsync);
  request.onreadystatechange = function() {
    if (request.readyState === 4) {
      window.location.reload(true);
    }
  };
  request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  request.send(postData);
}
})();


This post has been edited by Someguywith: May 27 2019, 16:13
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post May 27 2019, 16:06
Post #42
Someguywith



Astolfo~
*********
Group: Gold Star Club
Posts: 7,427
Joined: 27-September 15
Level 397 (Godslayer)


QUOTE(Someguywith @ May 22 2019, 20:10) *

I didn't like that you can't sort the bounties, so I fixed that. Can sort on date, name, type, status, reward and uploader

Code taken from Stack overflow/ an outdated reward sorter back from the g.e- days.


In the vein of my last script I added the same functionallity but then inside of the bounty list.

CODE
// ==UserScript==
// @name            Sort Bounties By Reward
// @description     Sort bounties by reward
// @include         https://e-hentai.org/bounty.php*
// @exclude         https://e-hentai.org/bounty.php?bid=*
// @version         2.0
// @namespace       SomeGuyWith, https://forums.e-hentai.org/index.php?showuser=2725435
// ==/UserScript==
(function() {

  /*** Settings ***/
  var hathToCredits = 4032
  var credits = 5000
  var hath = 0
  /*** End of Settings ***/

  var table = document.getElementsByClassName('itg');
  var rows = table[0].rows;
  var main = document.getElementById('s');
  var method = "POST";
  var postData = "grant_cred=" + credits + "&grant_hath=" + hath + "&addreward=Submit+Additional+Reward";
  var shouldBeAsync = true;
  var request = new XMLHttpRequest();

  // fix css
  main.style.width = '1330px';
  table[0].style.maxWidth = '99%';

  for (let row of rows) {
    if (row === rows[0]) {
      var head = row.insertCell(5);
      head.innerHTML = 'Quick Bump'
      head.style.backgroundColor = '#E0DED3'
      head.style.fontWeight = 'bold';
      head.style.padding = '3px 4px';
      head.style.height = '16px';
    } else {
      var cell = row.insertCell(5);
      var button = document.createElement('input');
      cell.innerHTML = '<input type="button" name="addreward" value="QB (C: ' + credits + ' H: ' + hath + ')" id="quickBump" style="width: 130px; line-height: 10px; min-height: 10px; padding-top: 2px">';
      cell.style.width = '135px';
      cell.addEventListener(
        "click", onClick, false
      );
    }
  }

  const comparer = (idx, asc) => (a, b) => ((v1, v2) =>
    v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2)
  )(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));

  document.querySelectorAll('th').forEach(th => th.addEventListener('click', (() => {
    const table = th.closest('table');
    Array.from(table.querySelectorAll('tr:nth-child(n+2)'))
      .sort(comparer(Array.from(th.parentNode.children).indexOf(th), this.asc = !this.asc))
      .forEach(tr => table.appendChild(tr));
  })));

  function getNumerical(txt) {
    var credits = txt.match(/([0-9, ]+)Credits/i);
    var hath = txt.match(/([0-9, ]+)Hath/i);
    var reward = 0;
    if (credits) {
      credits = parseInt(credits[1].replace(/[, ]/g, ''))
      reward += credits
    }
    if (hath) {
      hath = parseInt(hath[1].replace(/[, ]/g, ''))
      reward += (hath * hathToCredits)
    }
    return reward
  }

  const getCellValue = (tr, idx) => {
    if (idx === 4) {
      return getNumerical(tr.children[idx].innerText)
    } else {
      return tr.children[idx].innerText || tr.children[idx].textContent;
    }
  }

  function onClick(elem) {
    console.log(elem.path[2].cells[1].children[0].href)
    request.open(method, elem.path[2].cells[1].children[0].href, shouldBeAsync);
    request.onreadystatechange = function() {
      if (request.readyState === 4) {
        window.location.reload(true);
      }
    };
    request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    request.send(postData);
  }
})();


This post has been edited by Someguywith: May 27 2019, 17:06
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post May 28 2019, 10:37
Post #43
nawrawrawr



Lurker
Group: Gold Star Club
Posts: 2
Joined: 6-June 10
Level 180 (Ascended)


QUOTE(Someguywith @ May 26 2019, 21:40) *

There's a high reason why it's listed as "never be added". If you want to sort every gallary you get you first need to get every gallary. Some tags have well over hunderd thousand gallaries attached to them. So you'd first need to request all thous gallaries, which is already a huge strain on the server. Then you'll need to sort them, sorting a small list is fine, but again. hunderd thousands of results is going to bring any machine to a grinding halt till it's done processing.


I definitely can see that issue now, thanks for thinking about it. I first imagined "Hey in case there are 2 or more pages, just make the script load all the pages in memory and sort from there" but... as you point out, one whoopie-search of a thousand pages and you're gonna hit the server hard - and your image limit. Yikes.

QUOTE(Someguywith @ May 26 2019, 21:40) *

Something that is possible is to sort just one page of results, the issue is if the translated work is not on the same page it'll not be included next to the raw. But that would just defeat the purpose of what you'd want.

(That's atleast my asumption, if anyone who knows more sees this as wrong please feel free to correct me)

This would probably be the only sanitized solution to avoid the issue with the server being hit, but as you point out this would be a moot solution to [my] specific issue/request.


I guess, if this ever gets to that stage, is to limit page depth to, say, 5 pages and then give it a global cooldown so it can't be abused to DoS the server. In fact every page-load should probably be delayed. If anyone needs need more pages they can donate to E-H for Perks to show more results per page. Although 200 * 5 is still a lot for the server to handle imo. Thinking about it, E-H is surprisingly robust despite the way Perks increase load on it.

As much as I want this, it sounds more and more like a hassle... :}

Thanks for your time, though!
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Jul 25 2019, 11:18
Post #44
blue penguin



in umbra, igitur, pugnabimus
***********
Group: Gold Star Club
Posts: 10,046
Joined: 24-March 12
Level 500 (Godslayer)


Script Request

Dave wants an addon to the MPV which can display a slideshow at a controlled time between images. (that is to keep one's hands free)
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Sep 24 2019, 16:23
Post #45
blue penguin



in umbra, igitur, pugnabimus
***********
Group: Gold Star Club
Posts: 10,046
Joined: 24-March 12
Level 500 (Godslayer)


Script request

https://forums.e-hentai.org/index.php?showtopic=232235

One day i'll need to finally sort all this shit out (sorry)
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Sep 24 2019, 16:48
Post #46
Mayriad



SUPER ★ BUSY ★ TIME
*******
Group: Global Mods
Posts: 2,061
Joined: 18-December 10
Level 135 (Lord)


QUOTE(blue penguin @ Sep 24 2019, 16:23) *
Script request

https://forums.e-hentai.org/index.php?showtopic=232235

One day i'll need to finally sort all this shit out (sorry)

I have already completed this request.

Edit: oh wait, you probably meant that you are going to add it to the index as a fulfilled request? I thought completed requests do not need to be added because the last request I completed was not added.

This post has been edited by mayriad: Sep 29 2019, 15:02
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Oct 4 2019, 13:49
Post #47
Markerov



Lurker
Group: Lurkers
Posts: 3
Joined: 19-September 12


"In order to combat spam, your first post can't contain any URLs"
Hello, first time poster here! I encountered the aforementioned error message when trying to start a new thread for a script I wrote. Hopefully this one reply is enough for me to get my thread started. I'll update this post once I have a link.

Edit: Here it is: Enhanced Keyboard Navigation

This post has been edited by Markerov: Oct 4 2019, 13:51
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Oct 7 2019, 02:45
Post #48
blue penguin



in umbra, igitur, pugnabimus
***********
Group: Gold Star Club
Posts: 10,046
Joined: 24-March 12
Level 500 (Godslayer)


QUOTE(Markerov @ Oct 4 2019, 12:49) *
That's some nice stuff, thanks.

I wish violentmonkey (the one i use) would add GM_ aliases instead of using GM. for the grease monkey bindings. Making scripts portable is becoming a pain.

(And yes, I will sort this thread out someday, sorry)
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Oct 7 2019, 07:05
Post #49
Markerov



Lurker
Group: Lurkers
Posts: 3
Joined: 19-September 12


QUOTE(blue penguin @ Oct 7 2019, 08:45) *

I wish violentmonkey (the one i use) would add GM_ aliases instead of using GM. for the grease monkey bindings.


I'm not sure I understand, Violentmonkey use the GM_* style api. Or do you mean the other way round?
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Oct 7 2019, 13:54
Post #50
blue penguin



in umbra, igitur, pugnabimus
***********
Group: Gold Star Club
Posts: 10,046
Joined: 24-March 12
Level 500 (Godslayer)


QUOTE(Markerov @ Oct 7 2019, 06:05) *
I'm not sure I understand, Violentmonkey use the GM_* style api. Or do you mean the other way round?
The other way around, yes. This is what I get by writing things at 4AM for me.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Oct 21 2019, 17:37
Post #51
aaaplus



Newcomer
*
Group: Members
Posts: 16
Joined: 30-November 12
Level 26 (Apprentice)


a fix for general tag alias or just a cheap text replacer: (not my code, but copypasted post from page320 of the general tag thread)

install this with ur usual javascript userscript manager:
[greasyfork.org] https://greasyfork.org/en/scripts/10976-rep...n-webpages/code

open in any editor
find
CODE

var words  = {

put any replacements into any of the bracketed area after that, i.e.
CODE
'yuri | lesbians' : 'yuri',


and whatever else you can think of.

change the @includes to restrict it to just /g/ pages

don't know how efficient the code is

I'll probably write a generic regex version soon of the delete everything after vertical bar | variety.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Oct 22 2019, 01:26
Post #52
blue penguin



in umbra, igitur, pugnabimus
***********
Group: Gold Star Club
Posts: 10,046
Joined: 24-March 12
Level 500 (Godslayer)


QUOTE(aaaplus @ Oct 21 2019, 16:37) *
don't know how efficient the code is
You're right. That thing is fucking naive, running regexes over the entire DOM is as slow as you get.

QUOTE
I'll probably write a generic regex version soon of the delete everything after vertical bar | variety.
Give it a shot. I find this kind of script would be a good starter
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Dec 1 2019, 06:35
Post #53
Elemhunter



Newcomer
**
Group: Members
Posts: 97
Joined: 30-March 11
Level 28 (Apprentice)


Has there been any kind of script for gallery comment notifications? Even seeing a +1 next to a gallery would be useful. People think that they can ask questions in galleries you uploaded a year ago instead of messaging you.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Dec 1 2019, 16:50
Post #54
blue penguin



in umbra, igitur, pugnabimus
***********
Group: Gold Star Club
Posts: 10,046
Joined: 24-March 12
Level 500 (Godslayer)


QUOTE(Elemhunter @ Dec 1 2019, 04:35) *

Has there been any kind of script for gallery comment notifications? Even seeing a +1 next to a gallery would be useful. People think that they can ask questions in galleries you uploaded a year ago instead of messaging you.
Hhhmm. Reasonable for a script request, kind fo doable if one creates a "watch this gallery" button and keeps the data in local storage.

Watching every gallery would bow your browser storage quite fast and probably ban you for too many requests.

That said, if anyone wishes to take on such a script, let me go with a warning: comments are for the gallery not for flaming people. I can hardly see such a script being used for good purposes.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Dec 4 2019, 20:23
Post #55
Elemhunter



Newcomer
**
Group: Members
Posts: 97
Joined: 30-March 11
Level 28 (Apprentice)


Ah, you might be right about the page requests part. What a hassle.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Dec 9 2019, 06:33
Post #56
ezdiy



Newcomer
*
Group: Recruits
Posts: 12
Joined: 10-May 19


CODE

// ==UserScript==
// @name         EHMassTorrent
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        https://e-hentai.org/?*f_search=*
// @grant        none
// ==/UserScript==

(function() {
    var slack = 0.9;
    var seedtrump = 1.5;
    var minseeds = 2;
    'use strict';
    function gid(n) {
        return document.getElementById(n);
    }
    function gcls(n) {
        return document.getElementsByClassName(n);
    }
    function fget(n, def) {
        var v = gid(n).value || sessionStorage.getItem(n) || def;
        if (def !== undefined) {
            gid(n).value = v;
        }
        sessionStorage.setItem(n, v);
        return v;
    }
    function fset(n, v) {
        if (v === undefined) {
            v = fget(n);
        }
        gid(n).value = v;
        sessionStorage.setItem(n,v);
    }
    document.getElementById('dms').insertAdjacentHTML('afterbegin',`
<table>
<tr>
<td>Next delay<td><input type=text id="nd" style="width: 30px;"></input>
<td>Num pages<td><input type=text id="np" style="width: 30px;"></input>
<td>Pos<td><input type=text id="pos" style="width: 30px;"></input>/<td id=pcnt></td>
<td><button id="mstart">Start</button>
<td id=stat>
</table>`);
    fget('nd', 8000);
    fget('np', 0);
    fget('pos', 0);
    var isRunning = false;
    var startPos = 0;
    gid('mstart').addEventListener('click', function() {
        if (!isRunning) {
            startRunning();
        } else {
            stopRunning();
        }
    });
    var children = gcls('gldown');
    gid('pcnt').innerText = children.length;
    var stat = gid('stat');
    var pos;
    var prev;
    function startRunning() {
        sessionStorage.setItem('forceStart', 0);
        pos = fget('pos', 0);
        function progress() {
            if (prev) {
                prev.style.backgroundColor = '';
            }
            if (!isRunning) {
                return;
            }
            var dl = children[pos];
            var np = fget('np')|0;
            // we're out. browse to next page, or stop if numpages goes to 0
            if (np <= 0 || dl === undefined) {
                var newLoc = document.getElementsByClassName('ptt')[0].firstChild.firstChild.lastChild.firstChild.href;
                if (np <= 1 || !newLoc) {
                    fset('np', 0);
                    fset('pos', 0);
                    stat.innerText = "No more pages requested, halted.";
                    stopRunning();
                    return;
                }
                stat.innerText = "About to jump to next next page...";
                setTimeout(function() {
                    fset('np', np-1);
                    fset('pos', 0);
                    sessionStorage.setItem('forceStart', 1);
                    document.location = newLoc;
                }, Math.random() * (fget('nd')|0) + (fget('nd')|0));
                return;
            }
            var parent = dl.parentNode.parentNode;
            prev = parent;
            parent.style.backgroundColor = '#886';
            var url = dl.firstChild.href;
            if (!url || localStorage.getItem(url)=="1") {
                console.log(url + " is already known or has no torrents; skipping");
                pos++;
                fset('pos',pos);
                setTimeout(progress, 0);
                return;
            }

            var iframe = document.createElement('iframe');
            iframe.src = url;
            iframe.style.visibility = "hidden";
            iframe.style.width = 0;
            iframe.style.height = 0;
            iframe.style.border = "0 none";
            iframe.style.position = "absolute";
            iframe.onload = function() {
                stat.innerText = "Loaded iframe, fetching torrent";
                var forms = iframe.contentDocument.getElementsByTagName('form');
                var tuples = [];
                var best = -1;
                var i;
                for (i = 0; i < forms.length-1; i++) {
                    var td = forms[i].getElementsByTagName('td');
                    var dfunc = td[8].getElementsByTagName('a')[0].href;
                    var seeds = td[3].innerText.split(':')[1].substr(1)|0;
                    var size = eval(td[1].innerText.split(':')[1].replace('GB', '*1024*1024*1024').replace('MB', '*1024*1024').replace('KB','*1024').replace('B',''));
                    tuples.push([dfunc,seeds,size]);
                    // found larger torrent with some seeds
                    if (seeds > minseeds && (best == -1 || size > tuples[best][2])) {
                        best = i;
                    }
                }
                var best2 = best;
                if (best != -1) {
                    var bestt = tuples[best];
                    // now scan tuples again. if they're smaller by 'slack' (90%), but have more seeds 'seedtrump' (150%) of best torrent, choose that one instead
                    for (i = 0; i < tuples.length; i++) {
                        if (tuples[i][2] > bestt[2] * slack && tuples[i][1] > bestt[1] * seedtrump) {
                            console.log("TRUMP",best2,"=>",i);
                            best2 = i;
                        }
                    }
                    // best2 is our final selection
                    localStorage.setItem(url, "1");
                    console.log("Downloading " + url + " torrent index " + best2);
                    var durl = tuples[best2][0];
                    document.location = durl;
                }
                document.body.removeChild(iframe);
                pos++;
                fset('pos',pos);
                setTimeout(progress, Math.random() * (fget('nd')|0) * 2 + 300);
            }
            stat.innerText = "Loading iframe for " + url;
            document.body.appendChild(iframe);
        };
        isRunning = true;
        gid('mstart').innerText = "Stop";
        progress();
    }
    function stopRunning() {
        sessionStorage.getItem('forceStart', 0)
        isRunning = false;
        gid('mstart').innerText = "Start";
    }

    // Triggered by our forced 'next' click
    if (sessionStorage.getItem('forceStart')==1) {
        startRunning();
    }
})();


The workflow is: Specify narrow search query with stuff you want, then set numpages to something like 5 (5 * 25 = 125 torrents if you have 25 results per page). The script caches visited torrent download urls, so as to not hammer the server needlessly. The 8 seconds per torrent is reasonable value for gigabit home connection. If your torrenting is slow, you'll have to increase the step delay much higher (up to something like 50sec for typical cable). Otherwise you'll just bog down your torrent client. Browser must be set up to open torrent automatically and permit download of multiple files, and torrent client should auto-open likewise (qBT has such option for instance).

This post has been edited by ezdiy: Dec 9 2019, 07:02
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Dec 9 2019, 18:34
Post #57
blue penguin



in umbra, igitur, pugnabimus
***********
Group: Gold Star Club
Posts: 10,046
Joined: 24-March 12
Level 500 (Godslayer)


^ Yep, that works.

I see that you are being careful and are adding an 8s delay between every pageload. A small delay between each page load was pretty much my only worry with a script that would get all torrents from a query.

Pretty neat work. I have added the script to the OP.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Mar 3 2020, 10:26
Post #58
EvaOtaku07



Active Poster
*******
Group: Members
Posts: 2,258
Joined: 28-July 08
Level 274 (Destined)


Are there any scripts that auto-redirect fjorded galleries?

-SNIP-
but it's not working.

This post has been edited by blue penguin: Mar 3 2020, 18:22
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Mar 3 2020, 18:22
Post #59
blue penguin



in umbra, igitur, pugnabimus
***********
Group: Gold Star Club
Posts: 10,046
Joined: 24-March 12
Level 500 (Godslayer)


QUOTE(EvaOtaku07 @ Mar 3 2020, 08:26) *

Are there any scripts that auto-redirect fjorded galleries?
There are. But not here - for reasons
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Mar 4 2020, 01:35
Post #60
EvaOtaku07



Active Poster
*******
Group: Members
Posts: 2,258
Joined: 28-July 08
Level 274 (Destined)


Dumb question to ask here I realize, sorry.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post


8 Pages V < 1 2 3 4 5 > » 
Reply to this topicStart new topic
2 User(s) are reading this topic (2 Guests and 0 Anonymous Users)
0 Members:

 


Lo-Fi Version Time is now: 1st April 2025 - 15:09