raingart / Nova-YouTube-extension

Apache License 2.0
218 stars 11 forks source link

Update time-remaining.js: add Playback Rate #184

Open muescha opened 3 months ago

muescha commented 3 months ago

What:

Questions: 1) Should this be implemented in the current plugin, or should it be a separate plugin independent of the time-remaining plugin? A separate plugin would be code duplication, but might more clear in the options dialog. 2) Should it be added as an additional option to time-remaing, similar to "time_remaining_position," with a setting like show_playbackRate: yes/no? However, this would limit the customization of its position in the template string. 3) Should playbackRate be included in all format templates where speed is relevant?

muescha commented 3 months ago

Bildschirmfoto 2024-08-09 um 14 46 06

Bildschirmfoto 2024-08-09 um 14 47 01

raingart commented 3 months ago

Hi @muescha

the current implementation involves choosing from a given list of templates. But there is an alternative option. Which was not included for reasons of obviousness to users. In it the user can enter the selected format himself

https://github.com/raingart/Nova-YouTube-extension/blob/master/plugins/control-panel/time-remaining.js#L139-L179

You can try uncommenting. If this option suits you, then I will leave it. I assumed that the user is stupid and will not be able to figure it out. It’s easier and safer to choose from a ready-list. Because there are no visual hints for the user. And as you previously issue, there are quite big problems with the Wiki. And it was difficult for me to convey the possibilities clearly and clearly to the user. And laziness of course.

If you have any problems or questions, write here or by email, I will try to answer and help you.

muescha commented 3 months ago

yes - the first strategy with user edited templates are a lot more complicated.

Bildschirmfoto 2024-08-09 um 19 30 53

{left}/{left*speed} ({done%}) {speed}x

muescha commented 3 months ago

I think the current state is better to understand by an user.

so leaving the question 1-3:

it is up to you what would be the best implementation.

muescha commented 3 months ago

I generated the userscript right from the github repo (created a script: #186) what is different to the dev ver?

muescha commented 3 months ago

with the video I got it: it shows nothing because the dropdown was filtered by the exisiting template, because of no match there was no value.

I would redesign the template filed in the form of:

Label Value Example
speed {speed} 1.5
left {left} 00:02:30
left% {left%} 25%
left*speed {left*speed} 00:01:40
done {done} 00:07:30
done% {done%} 75%
duration {duration} 00:10:00
duration*speed {duration*speed} 00:06:40
muescha commented 3 months ago

thx for the time-remaining.txt - is the current state in any branch?

raingart commented 3 months ago

what is different to the dev ver?

the structure itself remains the same, just a little refactoring and fixing. Since I wrote it myself, git push occurred when cumulative changes denoting a new release.

branch now updated

Changelog.md:

new plugin

removed plugin:

fixes in plugins:

optimized plugins:

minor optimized plugins:

raingart commented 3 months ago

I don't know git very well That's why I added you to Collaborators I think it will be easier for you this way than when I guess to move this commit to a new branch git cherry-pick

and even more so solve “branch has conflicts”!

raingart commented 3 months ago

change any files and documentation as you see fit

raingart commented 3 months ago

I simplifying the format a little. datalist is not suitable for displaying data from 3 columns. It is more adapted for 2nd.

I also made a few examples at the beginning (I think they are the most popular, maybe) and then a list of all available commands

Screenshot from 2024-08-10 15-41-30

muescha commented 3 months ago

That looks great :)

muescha commented 3 months ago

I tried also a switch function - and found some problems in options.js - i tried to use 'data-dependent': { 'time_remaining_format_use_custom': false }, but this was only possible without the changes in options.js

see https://github.com/muescha/Nova-YouTube-extension/commit/542aa105f51df458e8b1f968824dd748298bdc13

Changes

In the line 100 this check skipped all rule tests if a checkbox is checked and if there is a data-dependent with a false value: it did not do the check.

Note: I am not aware of other side effects with this change.

(subtargetEl.checked && !subtargetEl.matches('[type="radio"]'))

Draft:

Bildschirmfoto 2024-08-10 um 23 18 11 Bildschirmfoto 2024-08-10 um 23 17 56

muescha commented 3 months ago

I tried with radio boxes but they are not that nice because I can not write in one line: - time pattern: (x) custom ( ) templates


      time_remaining_format_use_custom_radio_1: {
         _tagName: 'input',
         label: 'Use custom template',
         type: 'radio',
         name: `time_remaining_format_use_custom_radio`,
         checked: true,
         value: `true`,
      },
      time_remaining_format_use_custom_radio_2: {
         _tagName: 'input',
         label: 'Use pattern templates',
         type: 'radio',
         name: `time_remaining_format_use_custom_radio`,
         value: `false`,
      },

Bildschirmfoto 2024-08-10 um 23 56 57 Bildschirmfoto 2024-08-10 um 23 56 49

note: I don't found code snippets about radio so I added some info to the wiki (https://github.com/raingart/Nova-YouTube-extension/wiki/plugin#radio)

raingart commented 3 months ago
  1. originally a function attrDependencies (code) had only one function: hide all options when the plugin is deactivated.
  2. Then there was a need to display options that depend on other (parent) options.
  3. Adding inversion by specifying the ! sign at the beginning code
  4. And the last iteration is adding a similar function and turning off conflicting functions code

my short-sightedness led to the fact that instead of some universal method there was a modification of the attrDependencies that was initially not designed for this module.

that is, such use cases are available

it is also possible to "overlap" options. Because they are processed sequentially. You can make a mistake where two or more options may not work correctly.

Here is the entire list of data formats that I know and use that are saved: Screenshot from 2024-08-11 11-45-05

The very idea of ​​implementing a more flexible module terrifies me. I don't have the slightest idea how to implement it. I compared it to the current implementation, which is very limited, but it already exists and somehow works.

for testing you can select the speed plugin covers almost all use cases

At the very beginning I tried to look for a ready-made solution, but I couldn’t find it. Perhaps if you put the instructions for LLM (GPT like) correctly, it will be able to generate a ready-made function. But I can't even describe the task. Since, as you previously indicated, the data storage system is not optimal and uses different data storage formats for similar types. For example, why are nets stored in String? The answer is simply because then the inversion (!) stops working. That is, one crippling implementation will ruin the subsequent ones

raingart commented 3 months ago

So I found a wonderful error that confirms the fragility and non-obviousness of the current implementation

doesn't work completely. I probably added just the inverse of the empty string in desperation https://github.com/raingart/Nova-YouTube-extension/blob/2437cb554a91c436ab3ad7bf91bd03729b5e5099/plugins/player/speed.js#L977

since the specified type is Boolean and not String https://github.com/raingart/Nova-YouTube-extension/blob/2437cb554a91c436ab3ad7bf91bd03729b5e5099/plugins/player/speed.js#L744

need fix { label: 'none', value: 'false' }, in speed.js#L744

despite the fact that when saved from convects into a Boolean ("NovaTube") "sync" : "undefined" => "{"rate_hotkey":false}"

muescha commented 3 months ago

Yes, the code is a bit fragile.

Initially, I attempted to use 'data-dependent': { 'time_remaining_format_use_custom': false }.

During debugging, I discovered that setting this value to true always works. However, this is not due to the check in || ruleValues.some(i => currentValuesList.includes(i.toString())), but rather because of the shortcut subtargetEl.checked.

I also found that regardless of the checkbox state, the value is always on; there is no off value, nor is there an empty value. Even when unchecked, the value remains on.

To address this, I made the following change:

- return [subtargetEl.value];
+ return [(subtargetEl.type == 'checkbox') ? subtargetEl.checked.toString() : subtargetEl.value];

I added toString() to ensure all values are treated as strings.

With this change, there's no need to change the boolean values at 'data-dependent' to string, since all values are now strings (thanks to subtargetEl.checked.toString() and currentValuesList.includes(i.toString())).

Additionally, I removed this check:

- (subtargetEl.checked && !subtargetEl.matches('[type="radio"]')) // skip radio (which is always checked. Unlike a checkbox)
+ false //(subtargetEl.checked && !subtargetEl.matches('[type="radio"]')) // skip radio (which is always checked. Unlike a checkbox)

The reason for this removal is that, otherwise, the code never reaches the negation check. I tested using !on and !true, but this line prevented the negation check when the checkbox was checked. I didn't account for any side effects with this change, so it may need to be reviewed and fine-tuned further.

muescha commented 3 months ago

BTW:

I played a little with the radio and added a fieldset:

Bildschirmfoto 2024-08-11 um 19 26 05

Bildschirmfoto 2024-08-11 um 19 24 57

this can be done if we have a _tagname: 'fieldset' element where the legend: 'abc' creates a legend html element, and we allow a field with children where all the child values goes into.

the style for the radio buttons would change to show the ( ) in front of the text.

here is the resulting html snippet for the screenshot:

<!--

ul ul ul {
    list-style-type: none;
}

li>label:before {
    content: "↪";
    margin: 0 .5em;
    color: #343a45;
}

 -->

<li class="item">
    <div class="info" tooltip="Remaining time until the end of the video" flow="up">
        <label for="time-remaining">Remaining time</label>
        <a href="https://github.com/raingart/Nova-YouTube-extension/wiki/plugins#time-remaining" target="_blank"
           title="More info">?</a>

    </div>
    <div class="opt">
        <input type="checkbox" name="time-remaining" id="time-remaining">
    </div>
    <ul data-dependent="{&quot;time-remaining&quot;:[true]}">
        <li><!--<label for="time_remaining_format_use_custom_radio_fieldset">select a template</label>-->
            <fieldset legend="selects a template" name="time_remaining_format_use_custom_radio_fieldset"
                      id="time_remaining_format_use_custom_radio_fieldset" class="collapse">
                <legend>Select pattern template</legend>
                <ul>
                    <li class=""><input type="radio" name="time_remaining_format_use_custom_radio" checked="true"
                                        value="true" id="time_remaining_format_use_custom_radio_1" class=""><label
                            for="time_remaining_format_use_custom_radio_1" class="collapse">Custom</label></li>
                    <li style=""><input type="radio" name="time_remaining_format_use_custom_radio" value="false"
                                        id="time_remaining_format_use_custom_radio_2" class=""><label
                            for="time_remaining_format_use_custom_radio_2" class="collapse">Templates</label></li>
                </ul>

            </fieldset>
        </li>
        <li style="
display:none"><label for="time_remaining_format_use_custom_radio_1" style="
">Use custom template</label><input type="radio" name="time_remaining_format_use_custom_radio" checked="true"
                                    value="true" id="time_remaining_format_use_custom_radio_1" class=""></li>
        <li style="
display:none"><label for="time_remaining_format_use_custom_radio_2">Use pattern templates</label><input type="radio"
                                                                                                        name="time_remaining_format_use_custom_radio"
                                                                                                        value="false"
                                                                                                        id="time_remaining_format_use_custom_radio_2"
                                                                                                        class="collapse">
        </li>
        <li data-dependent="{&quot;time_remaining_format_use_custom_radio&quot;:true}"
            tooltip="[^] - correction current playback speed" class=""><label for="time_remaining_format">Custom time
            pattern</label><input type="text" list="time_remaining_format_help_list"
                                  placeholder="{done%}/{duration^} ({rate})" minlength="4" maxlength="100"
                                  required="true" name="time_remaining_format" id="time_remaining_format"
                                  class="collapse"></li>
        <li>
            <datalist name="time_remaining_format_help_list" id="time_remaining_format_help_list">
                <option value="{done}/{duration} ({done%})">0:10/0:44 (23%)</option>
                <option value="{done^}/{duration^} {rate}">0:05/0:25 1.75x</option>
                <option value="{left}/{duration} • {left%}">-0:34/0:44 • -77%</option>
                <option value="{left^}/{duration^} {rate}">-0:19/0:25 1.75x</option>
                <option value="{left}/{duration} • {left^}/{duration^} ({done%}) {rate}">-2:24/18:00 • -0:48/6:00 (87%)
                    3x
                </option>
                <option value="{left} {left^} {left%} • {done} {done^} {done%} • {duration} {duration^} • {rate}">-2:24
                    -0:48 -13% • 15:36 5:12 87% • 18:00 6:00 • 3x
                </option>
                <option value=" ">For a custom template, you can use these fields:</option>
                <option value="{rate}">1.75x</option>
                <option value="{left}">-0:34</option>
                <option value="{left^}">-0:19</option>
                <option value="{left%}">-77%</option>
                <option value="{done}">0:10</option>
                <option value="{done^}">0:05</option>
                <option value="{done%}">23%</option>
                <option value="{duration}">0:44</option>
                <option value="{duration^}">0:25</option>
            </datalist>
        </li>
        <li data-dependent="{&quot;time_remaining_format_use_custom_radio&quot;:false}"
            tooltip="[^] - correction current playback speed" class="hide"><label for="time_remaining_format_templates">Time
            pattern templates</label><select required="true" name="time_remaining_format_templates"
                                             id="time_remaining_format_templates" disabled="">
            <option value="{left^}">{left^}</option>
            <option value="{left^} ({done%})">{left^} ({done%})</option>
            <option value="{left^} ({left%})">{left^} ({left%})</option>
            <option value="{left}/{left^} ({done%})">{left}/{left^} ({done%})</option>
            <option value="{left}">{left}</option>
            <option value="{left%}">{left%}</option>
            <option value="{done%}">{done%}</option>
            <option value="{done^}/{left^}">{done^}/{left^}</option>
            <option value="{done^}/{duration^}">{done^}/{duration^}</option>
            <option value="{left^}/{duration^}">{left^}/{duration^}</option>
            <option value="{left^}/{duration^} ({done%})">{left^}/{duration^} ({done%})</option>
            <option value="{left}/{left^} ({done%}) {rate}">{left}/{left^} {rate}</option>
        </select></li>
        <li><label for="time_remaining_position">Render section</label><select name="time_remaining_position"
                                                                               id="time_remaining_position">
            <option value="player">player</option>
            <option value="description">description</option>
        </select></li>
    </ul>
</li>
raingart commented 3 months ago

I tried to implement radio elements at the initial stages but I came to the conclusion that they are generally useless. This is a restriction analogue to select

it takes up more space and has no functional advantage

for example in Remaining time > Render section or other places. select is easier to expand if necessary

muescha commented 3 months ago

only advantage is that all options are better visible for the user. and yes - every select can be shown as radio or as select.

If you don't like the radio thing, then I don't invest time to implement it :)