mpv & change wallpaper

This commit is contained in:
2025-08-01 15:13:29 +02:00
parent 8c96a0f4c0
commit eeb268b632
89 changed files with 10963 additions and 15985 deletions

15
.scripts/waydroid-reload.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/env bash
function checkReturn {
echo "Executing: $@"
if ! "$@"; then
echo "Error runnning command"
exit 1
fi
}
checkReturn waydroid session stop
# checkReturn sudo waydroid upgrade # since I'm not using the default image
checkReturn sudo waydroid init -f
checkReturn sudo systemctl restart waydroid-container
checkReturn waydroid show-full-ui

View File

@@ -55,6 +55,7 @@
font-family: 'MesloLGM Nerd Font'; font-family: 'MesloLGM Nerd Font';
font-size: 60px; font-size: 60px;
margin-top: 5px; margin-top: 5px;
margin-right: 20px;
} }
.weather-updatetime { .weather-updatetime {

View File

@@ -29,19 +29,19 @@ UNITS=metric
## Make cache dir ## Make cache dir
if [[ ! -d "$cache_dir" ]]; then if [[ ! -d "$cache_dir" ]]; then
mkdir -p ${cache_dir} mkdir -p "${cache_dir}"
fi fi
## Get data ## Get data
get_weather_data() { get_weather_data() {
weather=`curl -sf "http://api.openweathermap.org/data/3.0/onecall?lat=${LAT}&lon=${LON}&exclude=minutely,hourly,daily&appid=${KEY}&units=${UNITS}"` weather=$(curl -sf "http://api.openweathermap.org/data/3.0/onecall?lat=${LAT}&lon=${LON}&exclude=minutely,hourly,daily&appid=${KEY}&units=${UNITS}")
echo ${weather} >&2 echo "${weather}" >&2
weather=$(echo "$weather" | jq -r ".current") weather=$(echo "$weather" | jq -r ".current")
if [ ! -z "$weather" ]; then if [ -n "$weather" ]; then
weather_temp=`echo "$weather" | jq ".temp" | cut -d "." -f 1` weather_temp=$(echo "$weather" | jq ".temp" | cut -d "." -f 1)
weather_icon_code=`echo "$weather" | jq -r ".weather[].icon" | head -1` weather_icon_code=$(echo "$weather" | jq -r ".weather[].icon" | head -1)
weather_description=`echo "$weather" | jq -r ".weather[].description" | head -1 | sed -e "s/\b\(.\)/\u\1/g"` weather_description=$(echo "$weather" | jq -r ".weather[].description" | head -1 | sed -e "s/\b\(.\)/\u\1/g")
#Big long if statement of doom #Big long if statement of doom
if [ "$weather_icon_code" == "50d" ]; then if [ "$weather_icon_code" == "50d" ]; then
@@ -108,17 +108,17 @@ get_weather_data() {
weather_icon=" " weather_icon=" "
weather_hex="#c0caf5" weather_hex="#c0caf5"
fi fi
echo "$weather_icon" > ${cache_weather_icon} echo "$weather_icon" > "${cache_weather_icon}"
echo "$weather_description" > ${cache_weather_stat} echo "$weather_description" > "${cache_weather_stat}"
echo "$weather_temp""°C" > ${cache_weather_degree} echo "$weather_temp""°C" > "${cache_weather_degree}"
echo "$weather_hex" > ${cache_weather_hex} echo "$weather_hex" > "${cache_weather_hex}"
date "+%Y-%m-%d %H:%M:%S" | tee ${cache_weather_updatetime} >/dev/null date "+%Y-%m-%d %H:%M:%S" | tee "${cache_weather_updatetime}" >/dev/null
else else
echo "Weather Unavailable" > ${cache_weather_stat} echo "Weather Unavailable" > "${cache_weather_stat}"
echo " " > ${cache_weather_icon} echo " " > "${cache_weather_icon}"
echo "-" > ${cache_weather_degree} echo "-" > "${cache_weather_degree}"
echo "#adadff" > ${cache_weather_hex} echo "#adadff" > "${cache_weather_hex}"
date "+%Y-%m-%d %H:%M:%S" | tee ${cache_weather_updatetime} >/dev/null date "+%Y-%m-%d %H:%M:%S" | tee "${cache_weather_updatetime}" >/dev/null
fi fi
} }
@@ -145,13 +145,13 @@ if [[ "$1" == "--getdata" ]]; then
get_weather_data get_weather_data
fi fi
elif [[ "$1" == "--icon" ]]; then elif [[ "$1" == "--icon" ]]; then
cat ${cache_weather_icon} cat "${cache_weather_icon}"
elif [[ "$1" == "--temp" ]]; then elif [[ "$1" == "--temp" ]]; then
cat ${cache_weather_degree} cat "${cache_weather_degree}"
elif [[ "$1" == "--hex" ]]; then elif [[ "$1" == "--hex" ]]; then
tail -F ${cache_weather_hex} tail -F "${cache_weather_hex}"
elif [[ "$1" == "--stat" ]]; then elif [[ "$1" == "--stat" ]]; then
cat ${cache_weather_stat} cat "${cache_weather_stat}"
elif [[ "$1" == "--updatetime" ]]; then elif [[ "$1" == "--updatetime" ]]; then
cat ${cache_weather_updatetime} cat "${cache_weather_updatetime}"
fi fi

View File

@@ -24,4 +24,4 @@ env = NVD_BACKEND,direct
env = XCURSOR_SIZE,24 env = XCURSOR_SIZE,24
env = HYPRCURSOR_SIZE,24 env = HYPRCURSOR_SIZE,24
env = ELECTRON_OZONE_PLATFORM_HINT,auto env = ELECTRON_OZONE_PLATFORM_HINT,auto
env = DISPLAY_DEVICE,nvidia_0 # or nvidia_0 env = DISPLAY_DEVICE,intel_backlight # or nvidia_0

View File

@@ -5,7 +5,7 @@
##! Apps ##! Apps
bind = Super, C, exec, code --password-store=gnome-libsecret # Launch VSCode (editor) bind = Super, C, exec, code --password-store=gnome-libsecret # Launch VSCode (editor)
bind = Super, E, exec, nautilus --new-window # Launch file manager bind = Super, E, exec, nautilus --new-window # Launch file manager
bind = Super, W, exec, firefox --new-window # Launch Firefox bind = Super, W, exec, zen --new-window # Launch Browser
bind = Super, X, exec, gnome-text-editor # Launch Text Editor bind = Super, X, exec, gnome-text-editor # Launch Text Editor
bind = Super, B, exec, killall btop || ghostty -e btop # Launch btop (system monitor) bind = Super, B, exec, killall btop || ghostty -e btop # Launch btop (system monitor)
bind = Super, Space, exec, eww open main --toggle # Launch dashboard (eww) bind = Super, Space, exec, eww open main --toggle # Launch dashboard (eww)

View File

@@ -1,2 +1,2 @@
preload = /home/kolkas/.config/backgrounds/arona-desks.jpg preload = /home/kolkas/.config/backgrounds/nanami.png
wallpaper = , /home/kolkas/.config/backgrounds/arona-desks.jpg wallpaper = , /home/kolkas/.config/backgrounds/nanami.png

3
mpv/.gitignore vendored
View File

@@ -1 +1,2 @@
lastopen.json # Shaders cache directory
shaders/cache

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2020 Oscar Manglaras Copyright (c) 2021 noelsimbolon
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

121
mpv/README.md Normal file
View File

@@ -0,0 +1,121 @@
# mpv config
![mpv logo](https://raw.githubusercontent.com/mpv-player/mpv.io/master/source/images/mpv-logo-128.png)
## Overview
**mpv** is a free (as in freedom and free beer), open-source, and cross-platform media player. It supports
a wide variety of media file formats, audio and video codecs, and subtitle types.
This repo contains my personal mpv configurations and scripts that I use and are significantly better than default mpv, VLC, and MPC. Before installing, please take your time to read this whole README as common issues can be easily solved by simply reading carefully.
## Preview
[![preview.png](https://i.postimg.cc/8zNHHPHy/preview.png)](https://postimg.cc/VdZnsw2M)
## Installation
### Windows
Here are the steps to install mpv and to use my configuration files on Windows:
* Download the latest 64bit mpv Windows build by shinchiro from [mpv.io/installation](https://mpv.io/installation/) or directly from [here](https://sourceforge.net/projects/mpv-player-windows/files/) and extract it wherever you please. This is now your mpv folder
* Run `mpv-install.bat`, which is located in `installer` folder, with administrator priviledges by right-clicking and selecting Run as administrator
* Download this repository as a ZIP file (or you can clone it using git)
* Create a folder named `portable_config` (**this is important**), located at the same directory as `mpv.exe`
* Extract or copy the contents of this repository that you have downloaded to the `portable_config` folder
* To make some scripts work, you need to modify them from the release a little bit:
* In order for the `mpv-gif.lua` script to work, it requires [FFmpeg](https://ffmpeg.org/) with libass enabled and accessible via terminal. See the [installation instructions](https://github.com/Scheliux/mpv-gif-generator#installation) from the script's source repository for further info.
* **(Optional)** By default, the `mpv-gif.lua` script saves GIFs to `C:/Program Files/mpv/gifs`. To modify this, open `gif.conf`, which is located in `portable_config/script-opts` folder, with a text editor and specify the `dir`, which is output directory for GIFs, as you please. For example `dir="C:/Users/USERNAME/Pictures/mpv-gifs"`.
* **(Optional)** Make your own mpv configuration. You can do that by modifying my configuration files and/or making your own from scratch or modifying others' configurations. Check out the [useful links](#useful-links) section for mpv configuration guides.
* You're all set up.
### Linux
Here are the steps to install mpv and to use my configuration files on Linux:
* Install mpv and xclip (clipboard CLI interface) using the package manager that comes with your Linux distribution. xclip is needed for [copy-time.lua](https://github.com/noelsimbolon/mpv-config/blob/linux/scripts/copy-time.lua) and [seek-to.lua](https://github.com/noelsimbolon/mpv-config/blob/linux/scripts/seek-to.lua) scripts to work properly. The package name for mpv and xclip might also vary depending on your Linux distribution. Here, I will make Arch Linux, that comes with `pacman` as its package manager, as an example
```
sudo pacman -S mpv xclip
```
If you, for example, use Fedora Linux, that comes with `dnf` as its package manager, you can install mpv and xclip with the following command instead.
```
sudo dnf install mpv xclip
```
If you use other Linux distributions, please refer to the documentation of your Linux distribution's package manager on how to install packages.
* Download this repository as a ZIP file (or you can clone it using git) and extract/copy it to your standard mpv configuration directory which is `~/.config/mpv`
* Some things to highlight:
* In order for the `mpv-gif.lua` script to work, it requires [FFmpeg](https://ffmpeg.org/) with libass enabled and accessible via terminal. See the [installation instructions](https://github.com/Scheliux/mpv-gif-generator#installation) from the script's source repository for further info.
* **(Optional)** By default, the `mpv-gif.lua` script saves GIFs to `~/Videos/mpv-gifs`. To modify this, open `gif.conf`, which is located in `portable_config/script-opts` folder, with a text editor and specify the `dir`, which is output directory for GIFs, as you please. For example `dir="~/Videos"`.
* **(Optional)** Make your own mpv configuration. You can do that by modifying my configuration files and/or making your own from scratch or modifying others' configurations. Check out the [useful links](#useful-links) section for mpv configuration guides.
* You're all set up.
## Scripts
Scripts from external sources:
* audio-visualizer.lua ([source](https://github.com/mfcc64/mpv-scripts#visualizerlua))\
Various audio visualization. It only works if you open audio files.
* autoload.lua ([source](https://github.com/mpv-player/mpv/blob/master/TOOLS/lua/autoload.lua))\
Automatically load playlist entries before and after the currently playing file, by scanning the directory.
* copy-time.lua ([source](https://github.com/linguisticmind/mpv-scripts/tree/master/copy-time))\
Copies current timecode in HH:MM:SS.MS format to clipboard. Cross-platform (Mac, Windows, Linux).
* cycle-commands.lua ([source](https://github.com/CogentRedTester/mpv-scripts#cycle-commands))\
Cycles through a series of commands on a keypress. Each iteration of the cycle can contain as many commands as one wants. Syntax details are at the top of the file.
* cycle-profile.lua ([source](https://github.com/CogentRedTester/mpv-scripts#cycle-profile))\
Cycles through a list of profiles sent via a script message and prints the profile-desc to the OSD. More details at the top of the file.
* modernz.lua ([source](https://github.com/Samillion/ModernZ))\
A modern OSC UI replacement for MPV that retains the functionality of the default OSC.
* mpv-gif.lua ([source](https://github.com/Scheliux/mpv-gif-generator))\
Script to generate GIFs from video playback. Requires FFmpeg with libass enabled. The exporting GIFs with subtitled currently doesn't work properly.
* playlistmanager.lua ([source](https://github.com/jonniek/mpv-playlistmanager))\
Allows you to see and interact with your playlist in an intuitive way.
* seek-to.lua ([source](https://github.com/dexeonify/mpv-config/blob/main/scripts/seek-to.lua))\
Seek to an absolute timestamp specified via keyboard input or pasted from clipboard.
* sponsorblock-minimal.lua ([source](https://codeberg.org/jouni/mpv_sponsorblock_minimal))\
Skip sponsor segments in YouTube videos.
* thumbfast.lua ([source](https://github.com/po5/thumbfast))\
High-performance on-the-fly thumbnailer for mpv. **The script does not display thumbnails on its own**, it is meant to be used alongside a UI script that calls thumbfast.
Configuration files for these scripts can be found in the `script-opts` folder. I also modified some of these scripts' default keybindings. To see my modifications, look for script keybindings in `input.conf`.
## Shaders
The shaders included in the `shaders` folder:
* ArtCNN_C4F32 ([source](https://github.com/Artoriuz/ArtCNN/blob/main/GLSL/ArtCNN_C4F32.glsl))\
Used for luma upscaling.
* nnedi3-nns128-win8x4 ([source](https://github.com/bjin/mpv-prescalers/tree/master))\
Used for luma upscaling.
Use shaders based on your preference and system capabilities. For more info about shaders, read the resources in the [useful links](#useful-links) section.
## Useful Links
* [mpv tutorial](https://thewiki.moe/tutorials/mpv/) by The Wiki
* [mpv.conf guide](https://iamscum.wordpress.com/guides/videoplayback-guide/mpv-conf/) by iamscum
* [mpv Configuration Guide for Watching Videos](https://kokomins.wordpress.com/2019/10/14/mpv-config-guide/) by Kokomins
* [mpv Resampling](https://artoriuz.github.io/blog/mpv_upscaling.html) by João Vitor Chrisóstomo
## Official Links
* [mpv homepage](https://mpv.io/)
* [mpv wiki](https://github.com/mpv-player/mpv/wiki)
* [mpv FAQ](https://github.com/mpv-player/mpv/wiki/FAQ)
* [mpv manual](https://mpv.io/manual/stable/)
* [mpv User Scripts](https://github.com/mpv-player/mpv/wiki/User-Scripts)

View File

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

@@ -1,195 +1,49 @@
# vim: syntax=config # Check the following link for mpv's default keybindings:
# https://github.com/mpv-player/mpv/blob/master/etc/input.conf
# 左键单击暂停/双击全屏 # ========== CUSTOM KEYBINDINGS ==========
# MOUSE_BTN0 cycle pause
MBTN_LEFT_DBL cycle fullscreen
MBTN_LEFT cycle pause
# 滚轮控制音量 # GENERAL
AXIS_UP add volume +2 k cycle ontop
AXIS_DOWN add volume -2
# 快进和后退 # VIDEO
RIGHT osd-msg-bar seek +2 relative+keyframes d cycle deband
LEFT osd-msg-bar seek -2 relative+keyframes D cycle deinterlace
l osd-msg-bar seek +2 relative+keyframes n cycle video-unscaled
h osd-msg-bar seek -2 relative+keyframes C cycle-values video-aspect-override "16:9" "4:3" "2.35:1" "-1" # cycle the video aspect ratio ("-1" is the container aspect)
SHIFT+RIGHT osd-msg-bar seek +10 relative+keyframes
SHIFT+LEFT osd-msg-bar seek -10 relative+keyframes
L osd-msg-bar seek +10 relative+keyframes
H osd-msg-bar seek -10 relative+keyframes
# 音量 # AUDIO
UP add volume +2 a cycle audio
A cycle audio down
WHEEL_UP add volume 2
WHEEL_DOWN add volume -2
UP add volume 2
DOWN add volume -2 DOWN add volume -2
k add volume +2 x add audio-delay -0.05
j add volume -2 X add audio-delay +0.05
SHIFT+UP add volume +10
SHIFT+DOWN add volume -10
K add volume +10
J add volume -10
# 亮度 # SUBTITLES
. add brightness +1 Shift+g add sub-scale +0.05 # increase the subtitle font size
, add brightness -1 Shift+f add sub-scale -0.05 # decrease the subtitle font size
E add sub-gauss +0.1 # https://mpv.io/manual/stable/#options-sub-gauss
R add sub-gauss -0.1
z add sub-delay -0.05 # shift subtitles 50 ms earlier
Z add sub-delay +0.05 # shift subtitles 50 ms later
u cycle sub-gray # https://mpv.io/manual/stable/#options-sub-gray
U cycle blend-subtitles # https://mpv.io/manual/stable/#options-blend-subtitles
p cycle sub-fix-timing # https://mpv.io/manual/stable/#options-sub-fix-timing
g sub-reload # https://mpv.io/manual/stable/#command-interface-sub-reload
l cycle-values sub-ass-override "yes" "force" "no" # https://mpv.io/manual/stable/#options-sub-ass-override
# 播放下一个/上一个 # SCRIPT KEYBINDINGS
~ script-message cycle-commands "apply-profile HDR ; show-text 'HDR profile applied'" "apply-profile HDR restore ; show-text 'HDR profile restored'"
ALT+h playlist-prev ; show-text "${playlist-pos-1}/${playlist-count}" # ~ script-message cycle-commands "apply-profile Clip ; show-text 'Clip profile applied'" "apply-profile Mobius ; show-text 'Mobius profile applied'" "apply-profile Reinhard ; show-text 'Reinhard profile applied'" "apply-profile Hable ; show-text 'Hable profile applied'" "apply-profile bt.2390 ; show-text 'bt.2390 profile applied'" "apply-profile Gamma ; show-text 'Gamma profile applied'" "apply-profile Linear ; show-text 'Linear profile applied'"
PGUP playlist-prev ; show-text "${playlist-pos-1}/${playlist-count}" c script-binding cycle-visualizer # cycle audio visualizer (audio-visualizer.lua)
b script-binding set_gif_start # set the start timestamp for to make GIF (mpv-gif.lua)
ALT+l playlist-next ; show-text "${playlist-pos-1}/${playlist-count}" B script-binding set_gif_end # set the stop timestamp for to make GIF (mpv-gif.lua)
PGDWN playlist-next ; show-text "${playlist-pos-1}/${playlist-count}" ctrl+b script-binding make_gif # make the GIF using start and stop timestamps (mpv-gif.lua)
ctrl+B script-binding make_gif_with_subtitles # make the GIF using start and stop timestamps with subtitles (doesn't seem to work) (mpv-gif.lua)
# 显示播放信息 ctrl+c script-binding copy-time # copy current timestamp to clipboard in HH:MM:SS.MS format (copy-time.lua)
CTRL+i script-binding stats/display-stats-toggle ctrl+S script-binding toggle-seeker # toggle keyboard input to seek to inputted timestamp (seek-to.lua)
ctrl+v script-binding paste-timestamp # automatically seek to pasted timestamp from clipboard (seek-to.lua)
# 音轨 alt+b script-binding sponsorblock # toggle sponsorblock on/off (sponsorblock-minimal.lua)
a script_message audio-menu # 打开音轨菜单
A cycle audio # 下一个音轨
# 第一字幕列表选择
s script_message subtitle-menu# 打开字幕菜单
# # 第一字幕的下一个字幕
S cycle sub
# # 第二字幕的下一个字幕
# ALT+d cycle secondary-sid
# # 是否显示字幕 # cycle through subtitles
CTRL+s cycle sub-visibility
# 播放速度
ALT+b add speed +0.05
B add speed -0.05
CTRL+b set speed 1.0
# 音轨延迟
ALT+n add audio-delay +0.10
N add audio-delay -0.10
CTRL+n set sub-delay 0
# 字幕延迟
ALT+m add sub-delay +0.10
M add sub-delay -0.10
CTRL+m set sub-delay 0
# 字幕大小和位置
t add sub-scale -0.05 # decrease subtitle font size
r add sub-scale +0.05 # increase subtitle font size
T add sub-pos -1 # move subtitles up
R add sub-pos +1 # move subtitles down
CTRL+t set sub-scale 1.2
CTRL+r set sub-pos 100
# f 全屏,这个是默认的
SPACE cycle pause #暂停
IDEOGRAPHIC_SPACE cycle pause
m cycle mute #静音
CTRL+p show-progress
# 媒体按键
MENU show-progress
PLAY cycle pause
PAUSE cycle pause
PLAYPAUSE cycle pause
FORWARD osd-msg-bar seek +5 relative keyframes
REWIND osd-msg-bar seek -5 relative keyframes
VOLUME_UP add volume +2 ; show-text "Volume: ${volume}"
VOLUME_DOWN add volume -2 ; show-text "Volume: ${volume}"
MUTE cycle mute
CLOSE_WIN quit
# 播放列表
# SHIFT+RETURN 打开列表
# UP/DOWN移动选择
# RETURN 打开
# ESC退出
SHIFT+ENTER script-binding playlistmanager/showplaylist
ALT+k script-binding playlistmanager/moveup
ALT+j script-binding playlistmanager/movedown
ENTER script-binding playlistmanager/playfile
ESC script-binding playlistmanager/hideplaylist
# 书签
# o 打开书签
# O 保存当前为书签
# ESC :关闭书签菜单
# UP/DOWN/j/k/J/K :浏览当前页面上的书签(按住可快速滚动)
# LEFT/RIGHT :浏览书签页面(按住可快速滚动)
# ENTER :加载当前选择的书签
# d/DEL :删除当前选择的书
o script_message bookmarker-menu
O script_message bookmarker-quick-save
d script_message bookmarker-menu
# 打开上次播放的
CTRL+l script_message lastopen
# 文件管理器
# ctrl + o 打开文件管理器
# alt + o 输入要打开的目录
# up/down 移动选择
# left/right 进入/离开目录
# Return 播放
#忽略
c ignore
e ignore
g ignore
i ignore
p ignore
q ignore
u ignore
v ignore
w ignore
x ignore
y ignore
z ignore
A ignore
C ignore
D ignore
E ignore
F ignore
G ignore
I ignore
P ignore
Q ignore
U ignore
V ignore
W ignore
X ignore
Y ignore
Z ignore
< ignore
> ignore
? ignore
/ ignore
[ ignore
] ignore
{ ignore
} ignore
\ ignore
| ignore
0 ignore
1 ignore
2 ignore
3 ignore
4 ignore
5 ignore
6 ignore
7 ignore
8 ignore
9 ignore
BS ignore
KP0 ignore
KP1 ignore
KP2 ignore
KP3 ignore
KP4 ignore
KP5 ignore
KP6 ignore
KP7 ignore
KP8 ignore
KP9 ignore

View File

@@ -1,123 +1,130 @@
# vim: syntax=config # ========== GENERAL ==========
profile=high-quality # Allows for higher quality playback on mpv
vo=gpu-next # https://mpv.io/manual/stable/#video-output-drivers-gpu
# gpu-api=vulkan offers better overall performance, but it sometimes breaks playback
# For displaying HDR content (not HDR -> SDR) "d3d11" is recommended (Windows only)
gpu-api=vulkan # https://mpv.io/manual/stable/#options-gpu-api
fullscreen=no # Start in fullscreen
force-seekable=yes # If the player thinks that the media is not seekable, force enable seeking
keep-open=always # Don't close the player after finishing the video,
# and playback will never automatically advance to the next file in the playlist
reset-on-next-file=pause # After playing the next file in the playlist,
# it will automatically play the file instead of a paused state
hwdec=vulkan # https://mpv.io/manual/stable/#options-hwdec
dither-depth=8 # This must be set to match your monitor's bit depth
scale-antiring=0.6 # https://mpv.io/manual/stable/#options-scale-antiring
########### # ========== SCALERS AND SHADERS ==========
# General #
###########
auto-window-resize=no
save-position-on-quit
input-ipc-server=/tmp/mpvsocket # listen for IPC on this socket
load-stats-overlay=no
load-auto-profiles=no
brightness=-8 scale=ewa_lanczossharp # Luma upscaler
monitorpixelaspect=1 dscale=mitchell # Luma downscaler
no-border # no window title bar cscale=ewa_lanczossharp # Chroma up&downscaler
msg-module # prepend module name to log messages gpu-shader-cache-dir='~~/shaders/cache' # https://mpv.io/manual/stable/#options-gpu-shader-cache-dir
msg-color # color log messages on terminal
term-osd-bar # display a progress bar on the terminal
use-filedir-conf # look for additional config files in the directory of the opened file
input-media-keys=no # enable/disable OSX media keys
cursor-autohide=1000 # autohide the curser after 1s
prefetch-playlist=yes
force-seekable=yes
screenshot-format=png # Only use these if you have high-end hardware
screenshot-png-compression=8 # glsl-shader="~~/shaders/nnedi3-nns128-win8x4.hook"
screenshot-template='~/down/%F (%P) %n' # glsl-shader="~~/shaders/ArtCNN_C4F32.glsl"
watch-later-directory='~/.mpv/watch_later'
write-filename-in-watch-later-config
watch-later-options-remove=fullscreen
hls-bitrate=max # use max quality for HLS streams
# ========== DEBANDING ==========
[default] # Banding is a visual artifact, visual artifacts should never be in a video.
# Example of banding: https://imgur.com/32d77H0
# Debanding is the process of removing said banding.
# 6 minute explanation of what causes banding: https://www.youtube.com/watch?v=h9j89L8eQQk
deband=no # Turn on only for videos with banding. (Keybind=d)
deband-iterations=2 # https://mpv.io/manual/stable/#options-deband-iterations
deband-threshold=64 # https://mpv.io/manual/stable/#options-deband-threshold
deband-range=17 # https://mpv.io/manual/stable/#options-deband-range
deband-grain=12 # https://mpv.io/manual/stable/#options-deband-grain
######### # ========== ON SCREEN DISPLAY AND ON SCREEN CONTROLLER ==========
# Cache #
#########
cache=auto osd-bar=no # Don't show a huge volume box on screen when turning the volume up/down
osc=no # Allows for custom OSC to be used https://github.com/cyl0/mpv-osc-morden-x
border=no # Optional for modern OSC, but recommended
cursor-autohide-fs-only=yes # If this option is given, the cursor is always visible in windowed mode
# In fullscreen mode, the cursor is shown or hidden according to --cursor-autohide
cursor-autohide=300 # Cursor hide in ms
osd-level=1 # https://mpv.io/manual/stable/#options-osd-level
osd-duration=1000 # Set the duration of the OSD messages in ms
hr-seek=yes # Select when to use precise seeks that are not limited to keyframes
# https://mpv.io/manual/stable/#options-hr-seek
osd-font='Verdana'
osd-font-size=20
osd-color='#FFFFFF' # Hex code for white
osd-border-color='#000000' # Hex code for black
osd-border-size=0.6 # Size for osd text and progress bar
osd-blur=0.2 # Gaussian blur factor. 0 means no blur applied (default)
############# # ========== LANGUAGE PRIORITY ==========
# OSD / OSC #
#############
osc=no
osd-level=1 # enable osd and display --osd-status-msg on interaction
osd-duration=2500 # hide the osd after x ms
osd-status-msg='${time-pos} / ${duration}${?percent-pos: (${percent-pos}%)}${?frame-drop-count:${!frame-drop-count==0: Dropped: ${frame-drop-count}}}\n${?chapter:Chapter: ${chapter}}'
osd-font='Source Han Sans CN' alang=ja,jp,jpn,en,eng # Audio language priority
osd-font-size=32 slang=en,eng # Subtitle language priority
osd-color='#CCFFFFFF' # ARGB format
osd-border-color='#DD322640' # ARGB format
osd-bar-align-y=0 # progress bar y alignment (-1 top, 0 centered, 1 bottom)
osd-border-size=2 # size for osd text and progress bar
osd-bar-h=2 # height of osd bar as a fractional percentage of your screen height
osd-bar-w=60 # width of " " "
############# # ========== AUDIO ==========
# Subtitles #
#############
sub-ass
demuxer-mkv-subtitle-preroll=yes # try to show embedded subs when seeking even when no index information is present volume=100 # default volume, 100 = unchanged
demuxer-mkv-subtitle-preroll-secs=2 audio-file-auto=fuzzy # Load external audio with (almost) the same name as the video
volume-max=200 # Max volume of the player
sub-auto=fuzzy # external subs don't have to match the file name exactly to autoload audio-pitch-correction=yes # https://mpv.io/manual/stable/#options-audio-pitch-correction
sub-file-paths-append=ass # search for external subs in these relative subdirectories
sub-file-paths-append=srt
sub-file-paths-append=sub
sub-file-paths-append=subs
sub-file-paths-append=subtitles
embeddedfonts=yes # use embedded fonts for SSA/ASS subs
sub-fix-timing=no # do not try to fix gaps (which might make it worse in some cases)
sub-ass-force-style=Kerning=yes # allows you to override style parameters of ASS scripts
sub-use-margins
sub-ass-force-margins
# the following options only apply to subtitles without own styling (i.e. not ASS but e.g. SRT)
sub-font="Source Han Sans CN"
sub-font-size=45
sub-color="#FFFFFFFF"
sub-border-color="#FF262626"
sub-border-size=3.2
sub-shadow-offset=1
sub-shadow-color="#33000000"
sub-scale=1.2
############# # ========== SUBTITLES ==========
# Languages #
#############
alang=eng,chi # automatically select these subtitles (decreasing priority) demuxer-mkv-subtitle-preroll=yes # https://mpv.io/manual/stable/#options-demuxer-mkv-subtitle-preroll
slang=zh,zh-cn,zh-sim # automatically select these audio tracks (decreasing priority) sub-fix-timing=no # https://mpv.io/manual/stable/#options-sub-fix-timing
sub-auto=all # https://mpv.io/manual/stable/#options-sub-auto
# The following options only apply to subtitles without own styling
sub-font='Netflix Sans Medium' # Specify font to use for subtitles that do not themselves specify a particular font
sub-font-size=40
sub-color='#FFFFFFFF'
sub-border-color='#FF000000'
sub-border-size=2.0
sub-shadow-offset=0
sub-spacing=0.0
######### # ========== SCREENSHOT ==========
# Audio #
#########
audio-file-auto=fuzzy # external audio doesn't has to match the file name exactly to autoload screenshot-format=png # Output format of screenshots
audio-pitch-correction=yes # automatically insert scaletempo when playing with higher speed screenshot-high-bit-depth=yes # Same output bitdepth as the video. Set it "no" if you want to save disc space
volume-max=200 # maximum volume in %, everything above 100 results in amplification screenshot-png-compression=1 # Compression of the PNG picture (1-9).
volume=80 # default volume, 100 = unchanged # Higher value means better compression, but takes more time
screenshot-directory="~/Pictures/mpv-screenshots" # Output directory
screenshot-template="%f-%wH.%wM.%wS.%wT-#%#00n" # Name format (filename-hour-minute-second-milisecond-number)
################ # ========== INTERPOLATION ==========
# Video Output #
################
profile=fast
vo=gpu-next
video-rotate=no
hwdec=auto
gpu-api=opengl
# Defaults for all profiles
# blend-subtitles=yes # Subtitle blending in scenechanges (smoother effect)
# video-sync=display-resample # Set the fps as the max of your monitor refresh rate (only useful and needed with "interpolation=yes)
# interpolation=yes # Enable interpolation
# tscale=oversample # Interpolation method
# ========== CACHE ==========
# cache=yes
# cache-on-disk=yes
# cache-dir="C:\mpv-cache"
# demuxer-max-bytes=1000MiB
# demuxer-readahead-secs=300
# demuxer-max-back-bytes=200MiB
# ========== AUTO PROFILES ==========
# Auto profile that automatically applies for WEB-DL anime that need some debanding
[WEB-DL]
profile-desc=WEB-DL Anime (HatSubs, SubsPlease, HorribleSubs, Erai-raws)
profile-cond=string.match(p.filename, "HatSubs")~=nil or string.match(p.filename, "SubsPlease")~=nil or string.match(p.filename, "HorribleSubs")~=nil or string.match(p.filename, "Erai%-raws")~=nil
deband=yes

View File

@@ -1,184 +0,0 @@
# mpv keybindings
#
# Location of user-defined bindings: ~/.config/mpv/input.conf
#
# Lines starting with # are comments. Use SHARP to assign the # key.
# Copy this file and uncomment and edit the bindings you want to change.
#
# List of commands and further details: DOCS/man/input.rst
# List of special keys: --input-keylist
# Keybindings testing mode: mpv --input-test --force-window --idle
#
# Use 'ignore' to unbind a key fully (e.g. 'ctrl+a ignore').
#
# Strings need to be quoted and escaped:
# KEY show-text "This is a single backslash: \\ and a quote: \" !"
#
# You can use modifier-key combinations like Shift+Left or Ctrl+Alt+x with
# the modifiers Shift, Ctrl, Alt and Meta (may not work on the terminal).
#
# The default keybindings are hardcoded into the mpv binary.
# You can disable them completely with: --no-input-default-bindings
# Developer note:
# On compilation, this file is baked into the mpv binary, and all lines are
# uncommented (unless '#' is followed by a space) - thus this file defines the
# default key bindings.
# If this is enabled, treat all the following bindings as default.
#default-bindings start
#MBTN_LEFT ignore # don't do anything
#MBTN_LEFT_DBL cycle fullscreen # toggle fullscreen
#MBTN_RIGHT cycle pause # toggle pause/playback mode
#MBTN_BACK playlist-prev # skip to the previous file
#MBTN_FORWARD playlist-next # skip to the next file
# Mouse wheels, touchpad or other input devices that have axes
# if the input devices supports precise scrolling it will also scale the
# numeric value accordingly
#WHEEL_UP add volume 2
#WHEEL_DOWN add volume -2
#WHEEL_LEFT seek -10 # seek 10 seconds backward
#WHEEL_RIGHT seek 10 # seek 10 seconds forward
## Seek units are in seconds, but note that these are limited by keyframes
#RIGHT seek 5 # seek 5 seconds forward
#LEFT seek -5 # seek 5 seconds backward
#UP seek 60 # seek 1 minute forward
#DOWN seek -60 # seek 1 minute backward
# Do smaller, always exact (non-keyframe-limited), seeks with shift.
# Don't show them on the OSD (no-osd).
#Shift+RIGHT no-osd seek 1 exact # seek exactly 1 second forward
#Shift+LEFT no-osd seek -1 exact # seek exactly 1 second backward
#Shift+UP no-osd seek 5 exact # seek exactly 5 seconds forward
#Shift+DOWN no-osd seek -5 exact # seek exactly 5 seconds backward
#Ctrl+LEFT no-osd sub-seek -1 # seek to the previous subtitle
#Ctrl+RIGHT no-osd sub-seek 1 # seek to the next subtitle
#Ctrl+Shift+LEFT sub-step -1 # change subtitle timing such that the previous subtitle is displayed
#Ctrl+Shift+RIGHT sub-step 1 # change subtitle timing such that the next subtitle is displayed
#Alt+left add video-pan-x 0.1 # move the video right
#Alt+right add video-pan-x -0.1 # move the video left
#Alt+up add video-pan-y 0.1 # move the video down
#Alt+down add video-pan-y -0.1 # move the video up
#Alt++ add video-zoom 0.1 # zoom in
#ZOOMIN add video-zoom 0.1 # zoom in
#Alt+- add video-zoom -0.1 # zoom out
#ZOOMOUT add video-zoom -0.1 # zoom out
#Ctrl+WHEEL_UP add video-zoom 0.1 # zoom in
#Ctrl+WHEEL_DOWN add video-zoom -0.1 # zoom out
#Alt+BS set video-zoom 0 ; set video-pan-x 0 ; set video-pan-y 0 # reset zoom and pan settings
#PGUP add chapter 1 # seek to the next chapter
#PGDWN add chapter -1 # seek to the previous chapter
#Shift+PGUP seek 600 # seek 10 minutes forward
#Shift+PGDWN seek -600 # seek 10 minutes backward
#[ multiply speed 1/1.1 # decrease the playback speed
#] multiply speed 1.1 # increase the playback speed
#{ multiply speed 0.5 # halve the playback speed
#} multiply speed 2.0 # double the playback speed
#BS set speed 1.0 # reset the speed to normal
#Shift+BS revert-seek # undo the previous (or marked) seek
#Shift+Ctrl+BS revert-seek mark # mark the position for revert-seek
#q quit
#Q quit-watch-later # exit and remember the playback position
#q {encode} quit 4
#ESC set fullscreen no # leave fullscreen
#ESC {encode} quit 4
#p cycle pause # toggle pause/playback mode
#. frame-step # advance one frame and pause
#, frame-back-step # go back by one frame and pause
#SPACE cycle pause # toggle pause/playback mode
#> playlist-next # skip to the next file
#ENTER playlist-next # skip to the next file
#< playlist-prev # skip to the previous file
#O no-osd cycle-values osd-level 3 1 # toggle displaying the OSD on user interaction or always
#o show-progress # show playback progress
#P show-progress # show playback progress
#i script-binding stats/display-stats # display information and statistics
#I script-binding stats/display-stats-toggle # toggle displaying information and statistics
#` script-binding console/enable # open the console
#z add sub-delay -0.1 # shift subtitles 100 ms earlier
#Z add sub-delay +0.1 # delay subtitles by 100 ms
#x add sub-delay +0.1 # delay subtitles by 100 ms
#ctrl++ add audio-delay 0.100 # change audio/video sync by delaying the audio
#ctrl+- add audio-delay -0.100 # change audio/video sync by shifting the audio earlier
#Shift+g add sub-scale +0.1 # increase the subtitle font size
#Shift+f add sub-scale -0.1 # decrease the subtitle font size
#9 add volume -2
#/ add volume -2
#0 add volume 2
#* add volume 2
#m cycle mute # toggle mute
#1 add contrast -1
#2 add contrast 1
#3 add brightness -1
#4 add brightness 1
#5 add gamma -1
#6 add gamma 1
#7 add saturation -1
#8 add saturation 1
#Alt+0 set current-window-scale 0.5 # halve the window size
#Alt+1 set current-window-scale 1.0 # reset the window size
#Alt+2 set current-window-scale 2.0 # double the window size
#b cycle deband # toggle the debanding filter
#d cycle deinterlace # cycle the deinterlacing filter
#r add sub-pos -1 # move subtitles up
#R add sub-pos +1 # move subtitles down
#t add sub-pos +1 # move subtitles down
#v cycle sub-visibility # hide or show the subtitles
#Alt+v cycle secondary-sub-visibility # hide or show the secondary subtitles
#V cycle sub-ass-vsfilter-aspect-compat # toggle stretching SSA/ASS subtitles with anamorphic videos to match the historical renderer
#u cycle-values sub-ass-override "force" "yes" # toggle overriding SSA/ASS subtitle styles with the normal styles
#j cycle sub # switch subtitle track
#J cycle sub down # switch subtitle track backwards
#SHARP cycle audio # switch audio track
#_ cycle video # switch video track
#T cycle ontop # toggle placing the video on top of other windows
#f cycle fullscreen # toggle fullscreen
#s screenshot # take a screenshot of the video in its original resolution with subtitles
#S screenshot video # take a screenshot of the video in its original resolution without subtitles
#Ctrl+s screenshot window # take a screenshot of the window with OSD and subtitles
#Alt+s screenshot each-frame # automatically screenshot every frame; issue this command again to stop taking screenshots
#w add panscan -0.1 # decrease panscan
#W add panscan +0.1 # shrink black bars by cropping the video
#e add panscan +0.1 # shrink black bars by cropping the video
#A cycle-values video-aspect-override "16:9" "4:3" "2.35:1" "-1" # cycle the video aspect ratio ("-1" is the container aspect)
#POWER quit
#PLAY cycle pause # toggle pause/playback mode
#PAUSE cycle pause # toggle pause/playback mode
#PLAYPAUSE cycle pause # toggle pause/playback mode
#PLAYONLY set pause no # unpause
#PAUSEONLY set pause yes # pause
#STOP quit
#FORWARD seek 60 # seek 1 minute forward
#REWIND seek -60 # seek 1 minute backward
#NEXT playlist-next # skip to the next file
#PREV playlist-prev # skip to the previous file
#VOLUME_UP add volume 2
#VOLUME_DOWN add volume -2
#MUTE cycle mute # toggle mute
#CLOSE_WIN quit
#CLOSE_WIN {encode} quit 4
#ctrl+w quit
#E cycle edition # switch edition
#l ab-loop # set/clear A-B loop points
#L cycle-values loop-file "inf" "no" # toggle infinite looping
#ctrl+c quit 4
#DEL script-binding osc/visibility # cycle OSC visibility between never, auto (mouse-move) and always
#ctrl+h cycle-values hwdec "auto-safe" "no" # toggle hardware decoding
#F8 show-text ${playlist} # show the playlist
#F9 show-text ${track-list} # show the list of video, audio and sub tracks
#
# Legacy bindings (may or may not be removed in the future)
#
#! add chapter -1 # seek to the previous chapter
#@ add chapter 1 # seek to the next chapter
#
# Not assigned by default
# (not an exhaustive list of unbound commands)
#
# ? cycle sub-forced-events-only # display only DVD/PGS forced subtitle events
# ? stop # stop playback (quit or enter idle mode)

View File

@@ -1,143 +0,0 @@
#
# Example mpv configuration file
#
# Warning:
#
# The commented example options usually do _not_ set the default values. Call
# mpv with --list-options to see the default values for most options. There is
# no builtin or example mpv.conf with all the defaults.
#
#
# Configuration files are read system-wide from /usr/local/etc/mpv.conf
# and per-user from ~/.config/mpv/mpv.conf, where per-user settings override
# system-wide settings, all of which are overridden by the command line.
#
# Configuration file settings and the command line options use the same
# underlying mechanisms. Most options can be put into the configuration file
# by dropping the preceding '--'. See the man page for a complete list of
# options.
#
# Lines starting with '#' are comments and are ignored.
#
# See the CONFIGURATION FILES section in the man page
# for a detailed description of the syntax.
#
# Profiles should be placed at the bottom of the configuration file to ensure
# that settings wanted as defaults are not restricted to specific profiles.
##################
# video settings #
##################
# Start in fullscreen mode by default.
#fs=yes
# force starting with centered window
#geometry=50%:50%
# don't allow a new window to have a size larger than 90% of the screen size
#autofit-larger=90%x90%
# Do not close the window on exit.
#keep-open=yes
# Do not wait with showing the video window until it has loaded. (This will
# resize the window once video is loaded. Also always shows a window with
# audio.)
#force-window=immediate
# Disable the On Screen Controller (OSC).
#osc=no
# Keep the player window on top of all other windows.
#ontop=yes
# Specify fast video rendering preset (for --vo=<gpu|gpu-next> only)
# Recommended for mobile devices or older hardware with limited processing power
#profile=fast
# Specify high quality video rendering preset (for --vo=<gpu|gpu-next> only)
# Offers superior image fidelity and visual quality for an enhanced viewing
# experience on capable hardware
#profile=high-quality
# Force video to lock on the display's refresh rate, and change video and audio
# speed to some degree to ensure synchronous playback - can cause problems
# with some drivers and desktop environments.
#video-sync=display-resample
# Enable hardware decoding if available. Often, this does not work with all
# video outputs, but should work well with default settings on most systems.
# If performance or energy usage is an issue, forcing the vdpau or vaapi VOs
# may or may not help.
#hwdec=auto
##################
# audio settings #
##################
# Specify default audio device. You can list devices with: --audio-device=help
# The option takes the device string (the stuff between the '...').
#audio-device=alsa/default
# Do not filter audio to keep pitch when changing playback speed.
#audio-pitch-correction=no
# Output 5.1 audio natively, and upmix/downmix audio with a different format.
#audio-channels=5.1
# Disable any automatic remix, _if_ the audio output accepts the audio format.
# of the currently played file. See caveats mentioned in the manpage.
# (The default is "auto-safe", see manpage.)
#audio-channels=auto
##################
# other settings #
##################
# Pretend to be a web browser. Might fix playback with some streaming sites,
# but also will break with shoutcast streams.
#user-agent="Mozilla/5.0"
# cache settings
#
# Use a large seekable RAM cache even for local input.
#cache=yes
#
# Use extra large RAM cache (needs cache=yes to make it useful).
#demuxer-max-bytes=500M
#demuxer-max-back-bytes=100M
#
# Disable the behavior that the player will pause if the cache goes below a
# certain fill size.
#cache-pause=no
#
# Store cache payload on the hard disk instead of in RAM. (This may negatively
# impact performance unless used for slow input such as network.)
#cache-dir=~/.cache/
#cache-on-disk=yes
# Display English subtitles if available.
#slang=en
# Play Finnish audio if available, fall back to English otherwise.
#alang=fi,en
# Change subtitle encoding. For Arabic subtitles use 'cp1256'.
# If the file seems to be valid UTF-8, prefer UTF-8.
# (You can add '+' in front of the codepage to force it.)
#sub-codepage=cp1256
# You can also include other configuration files.
#include=/path/to/the/file/you/want/to/include
############
# Profiles #
############
# The options declared as part of profiles override global default settings,
# but only take effect when the profile is active.
# The following profile can be enabled on the command line with: --profile=eye-cancer
#[eye-cancer]
#sharpen=5

View File

@@ -1 +0,0 @@
font_size=44

View File

@@ -1,175 +0,0 @@
#######################################################
# This is the default config file for mpv-file-browser
# https://github.com/CogentRedTester/mpv-file-browser
#######################################################
# root directories, separated by commas
# on linux you will probably want to add `/`,
# on windows this should be used to add different drive letters
# Examples:
# linux: root=~/,/
# windows: root=~/,C:/
root=~/
# characters to separate root directories, each character works individually
# this is in case one is using directories with strange names
root_separators=,;
# number of entries to show on the screen at once
num_entries=20
# wrap the cursor around the top and bottom of the list
wrap=no
# only show files compatible with mpv in the browser
filter_files=yes
# experimental feature that recurses directories concurrently when appending items to the playlist
# this feature has the potential for massive performance improvements when using addons with asynchronous IO
concurrent_recursion=no
# maximum number of recursions that can run concurrently
# if this number is too high it risks overflowing the mpv event queue, which will cause some directories to be dropped entirely
max_concurrency=16
# enable custom keybinds
# the keybind json file must go in ~~/script-opts
custom_keybinds=no
# file-browser only shows files that are compatible with mpv by default
# adding a file extension to this list will add it to the extension whitelist
# extensions are separated with the root separators, do not use any spaces
extension_whitelist=
# add file extensions to this list to disable default filetypes
# note that this will also override audio/subtitle_extension options below
extension_blacklist=
# files with these extensions will be added as additional audio tracks for the current file instead of appended to the playlist
# items on this list are automatically added to the extension whitelist
audio_extensions=mka,dts,dtshd,dts-hd,truehd,true-hd
# files with these extensions will be added as additional subtitle tracks for the current file instead of appended to the playlist
# items on this list are automatically added to the extension whitelist
subtitle_extensions=etf,etf8,utf-8,idx,sub,srt,rt,ssa,ass,mks,vtt,sup,scc,smi,lrc,pgs
# filter directories or files starting with a period like .config
# for linux systems
filter_dot_dirs=no
filter_dot_files=no
# substitude forward slashes for backslashes when appending a local file to the playlist
# may be useful on windows systems
substitute_backslash=no
# interpret backslashes `\` in paths as forward slashes `/`
# this is useful on Windows, which natively uses backslashes.
# As backslashes are valid filename characters in Unix systems this could
# cause mangled paths, though such filenames are rare.
# Use `yes` and `no` to enable/disable. `auto` tries to use the mpv `platform`
# property (mpv v0.36+) to decide. If the property is unavailable it defaults to `yes`.
normalise_backslash=auto
# this option reverses the behaviour of the alt+ENTER keybind
# when disabled the keybind is required to enable autoload for the file
# when enabled the keybind disables autoload for the file
autoload=no
# if autoload is triggered by selecting the currently playing file, then
# the current file will have it's watch-later config saved before being closed and re-opened
# essentially the current file will not be restarted
autoload_save_current=yes
# when opening the browser in idle mode prefer the current working directory over the root
# note that the working directory is set as the 'current' directory regardless, so `home` will
# move the browser there even if this option is set to false
default_to_working_directory=no
# when moving up a directory do not stop on empty protocol schemes like `ftp://`
# e.g. moving up from `ftp://localhost/` will move straight to the root instead of `ftp://`
skip_protocol_schemes=yes
# map optical device paths to their respective file paths,
# e.g. mapping bd:// to the value of the bluray-device property
map_bd_device=yes
map_dvd_device=yes
map_cdda_device=yes
# enables addons
addons=no
addon_directory=~~/script-modules/file-browser-addons
# directory to load external modules - currently just user-input-module
module_directory=~~/script-modules
# turn the OSC idle screen off and on when opening and closing the browser
# this should only be enabled if file-browser is the only thing controlling the idle-screen,
# if multiple sources attempt to control the idle-screen at the same time it can cause unexpected behaviour.
toggle_idlescreen=no
# Set the current open status of the browser in the `file_browser/open` field of the `user-data` property.
# This property is only available in mpv v0.36+.
set_user_data=yes
# Set the current open status of the browser in the `file_browser-open` field of the `shared-script-properties` property.
# This property is deprecated. When it is removed in mpv v0.37 file-browser will automatically disable this option.
set_shared_script_properties=no
####################################
######### style settings ###########
####################################
# force file-browser to use a specific text alignment (default: top-left)
# uses ass tag alignment numbers: https://aegi.vmoe.info/docs/3.0/ASS_Tags/#index23h3
# set to 0 to use the default mpv osd-align options
alignment=7
# The format string used for the header. Uses custom-keybind substitution codes to
# dynamically change the contents of the header. See: docs/custom-keybinds.md#codes
# e.g. to add file numbers, set this to: {\fnMonospace}[%i/%x]{\fn<font_name_header or blank>} %q\N----------------------------------------------------
format_string_header=%q\N----------------------------------------------------
# The format strings used for the wrappers. Supports custom-keybind substitution codes, and
# supports two additional codes: `%<` and `%>` to show the number of items before and after the visible list, respectively.
# Setting these options to empty strings will disable the wrappers.
format_string_topwrapper=%< item(s) above\N
format_string_bottomwrapper=\N%> item(s) remaining
# allows custom icons be set for the folder and cursor
# the `\h` character is a hard space to add padding
folder_icon={\p1}m 6.52 0 l 1.63 0 b 0.73 0 0.01 0.73 0.01 1.63 l 0 11.41 b 0 12.32 0.73 13.05 1.63 13.05 l 14.68 13.05 b 15.58 13.05 16.31 12.32 16.31 11.41 l 16.31 3.26 b 16.31 2.36 15.58 1.63 14.68 1.63 l 8.15 1.63{\p0}\h
cursor_icon={\p1}m 14.11 6.86 l 0.34 0.02 b 0.25 -0.02 0.13 -0 0.06 0.08 b -0.01 0.16 -0.02 0.28 0.04 0.36 l 3.38 5.55 l 3.38 5.55 3.67 6.15 3.81 6.79 3.79 7.45 3.61 8.08 3.39 8.5l 0.04 13.77 b -0.02 13.86 -0.01 13.98 0.06 14.06 b 0.11 14.11 0.17 14.13 0.24 14.13 b 0.27 14.13 0.31 14.13 0.34 14.11 l 14.11 7.28 b 14.2 7.24 14.25 7.16 14.25 7.07 b 14.25 6.98 14.2 6.9 14.11 6.86{\p0}\h
# set the opacity of fonts in hexadecimal from 00 (opaque) to FF (transparent)
font_opacity_selection_marker=99
# print the header in bold font
font_bold_header=yes
# scale the size of the browser; 2 would double the size, 0.5 would halve it, etc.
# the header and wrapper scaling is relative to the base scaling
scaling_factor_base=1
scaling_factor_header=1.4
scaling_factor_wrappers=0.64
# set custom font names, blank is the default
# setting custom fonts for the folder/cursor can fix broken or missing icons
font_name_header=
font_name_body=
font_name_wrappers=
font_name_folder=
font_name_cursor=
# set custom font colours
# colours are in hexadecimal format in Blue Green Red order
# note that this is the opposite order to most RGB colour codes
font_colour_header=00ccff
font_colour_body=ffffff
font_colour_wrappers=00ccff
font_colour_cursor=00ccff
# these are colours applied to list items in different states
font_colour_selected=fce788
font_colour_multiselect=fcad88
font_colour_playing=33ff66
font_colour_playing_multiselected=22b547

10
mpv/script-opts/gif.conf Normal file
View File

@@ -0,0 +1,10 @@
# ========== CONFIGURATION FILE FOR MPV-GIF.LUA ==========
# Sets the output directory
dir="$HOME/Videos/mpv-gifs"
# Sets the resolution of the output GIFs
rez=1920
# Sets the framerate of the output gifs. Default is 15. Don't go too overboard or the filesize will balloon
fps=23.976

View File

@@ -0,0 +1,382 @@
# Language and display
# set language (for available options, see: https://github.com/Samillion/ModernZ/blob/main/docs/TRANSLATIONS.md)
language=en
# font for the OSC (default: mpv-osd-symbols or the one set in mpv.conf)
font=mpv-osd-symbols
# show mpv logo when idle
idlescreen=yes
# show OSC window top bar: "auto", "yes", or "no" (borderless/fullscreen)
window_top_bar=auto
# show OSC when windowed
showwindowed=yes
# show OSC when fullscreen
showfullscreen=yes
# show OSC when paused
showonpause=no
# disable OSC hide timeout when paused
keeponpause=yes
# disable Santa hat in December
greenandgrumpy=no
# OSC behaviour and scaling
# time (in ms) before OSC hides if no mouse movement
hidetimeout=1500
# if seeking should reset the hidetimeout
seek_resets_hidetimeout=yes
# fade-out duration (in ms), set to 0 for no fade
fadeduration=200
# whether to enable fade-in effect
fadein=no
# minimum mouse movement (in pixels) required to show OSC
minmousemove=0
# show OSC only when hovering at the bottom
bottomhover=yes
# height of hover zone for bottomhover (in pixels)
bottomhover_zone=130
# show OSC when seeking
osc_on_seek=no
# show OSC on start of every file
osc_on_start=no
# pause video while seeking with mouse move (on button hold)
mouse_seek_pause=yes
# force show seekbar tooltip on mouse drag, even if not hovering seekbar
force_seek_tooltip=no
# scale osc with the video
vidscale=auto
# osc scale factor when windowed
scalewindowed=1.0
# osc scale factor when fullscreen
scalefullscreen=1.0
# Elements display
# show title in the OSC (above seekbar)
show_title=yes
# title above seekbar format: "${media-title}" or "${filename}"
title=${media-title}
# font size of the title text (above seekbar)
title_font_size=24
# chapter title font size
chapter_title_font_size=14
# show cached time information
cache_info=no
# show cache speed per second
cache_info_speed=no
# font size of the cache information
cache_info_font_size=12
# show chapter title alongside timestamp (below seekbar)
show_chapter_title=yes
# format for chapter display on seekbar hover (set to "no" to disable)
chapter_fmt=%s
# show total time instead of remaining time
timetotal=yes
# show timecodes with milliseconds
timems=no
# use the Unicode minus sign in remaining time
unicodeminus=no
# "dynamic" or "fixed". dynamic shows MM:SS when possible, fixed always shows HH:MM:SS
time_format=dynamic
# font size of the time display
time_font_size=16
# tooltips font size
tooltip_font_size=14
# Title bar settings
# show window title in borderless/fullscreen mode
window_title=no
# show window controls (close, minimize, maximize) in borderless/fullscreen
window_controls=yes
# same as title but for window_top_bar
windowcontrols_title=${media-title}
# Subtitle display settings
# raise subtitles above the OSC when shown
raise_subtitles=yes
# amount by which subtitles are raised when the OSC is shown (in pixels)
raise_subtitle_amount=125
# Buttons display and functionality
# show the jump backward and forward buttons
jump_buttons=yes
# change the jump amount in seconds
jump_amount=10
# change the jump amount in seconds when right-clicking jump buttons and shift-clicking chapter skip buttons
jump_more_amount=60
# show different icon when jump_amount is set to 5, 10, or 30
jump_icon_number=yes
# seek mode for jump buttons
jump_mode=relative
# enable continuous jumping when holding down seek buttons
jump_softrepeat=yes
# show the chapter skip backward and forward buttons
chapter_skip_buttons=no
# enable continuous skipping when holding down chapter skip buttons
chapter_softrepeat=yes
# show next/previous playlist track buttons
track_nextprev_buttons=yes
# show mute button and volume slider
volume_control=yes
# volume scale type: "linear" or "logarithmic"
volume_control_type=linear
# show playlist button: Left-click for simple playlist, Right-click for interactive playlist
playlist_button=yes
# hide playlist button when no playlist exists
hide_empty_playlist_button=no
# gray out the playlist button when no playlist exists
gray_empty_playlist_button=no
# show download button on web videos (requires yt-dlp and ffmpeg)
download_button=yes
# default download directory for videos (https://mpv.io/manual/master/#paths)
download_path=~/Videos/mpv Downloads/
# show screenshot button
screenshot_button=yes
# flag for screenshot button: "subtitles", "video", "window", "each-frame"
screenshot_flag=subtitles
# show window on top button
ontop_button=yes
# show loop button
loop_button=yes
# show speed control button
speed_button=yes
# speed change amount per click
speed_button_click=1
# speed change amount on scroll
speed_button_scroll=0.25
# show info button
info_button=yes
# show fullscreen toggle button
fullscreen_button=yes
# enable looping by right-clicking pause
loop_in_pause=yes
# force buttons to always be active. can add: playlist_prev,playlist_next
buttons_always_active=none
# icon size for the play/pause button
playpause_size=28
# icon size for the middle buttons
midbuttons_size=24
# icon size for the side buttons
sidebuttons_size=24
# show zoom controls in image viewer mode
zoom_control=yes
# maximum zoom in value
zoom_in_max=4
# minimum zoom out value
zoom_out_min=-1
# Colors and style
# accent color of the OSC and title bar
osc_color=#000000
# color of the title in borderless/fullscreen mode
window_title_color=#FFFFFF
# color of the window controls (close, minimize, maximize) in borderless/fullscreen mode
window_controls_color=#FFFFFF
# color of close window control on hover
windowcontrols_close_hover=#F45C5B
# color of maximize window controls on hover
windowcontrols_max_hover=#F8BC3A
# color of minimize window controls on hover
windowcontrols_min_hover=#43CB44
# color of the title (above seekbar)
title_color=#FFFFFF
# color of the cache information
cache_info_color=#FFFFFF
# color of the seekbar progress and handle
seekbarfg_color=#FB8C00
# color of the remaining seekbar
seekbarbg_color=#94754F
# color of the cache ranges on the seekbar
seekbar_cache_color=#918F8E
# match volume bar color with seekbar color (ignores side_buttons_color)
volumebar_match_seek_color=no
# color of the timestamps (below seekbar)
time_color=#FFFFFF
# color of the chapter title next to timestamp (below seekbar)
chapter_title_color=#FFFFFF
# color of the side buttons (audio, subtitles, playlist, etc.)
side_buttons_color=#FFFFFF
# color of the middle buttons (skip, jump, chapter, etc.)
middle_buttons_color=#FFFFFF
# color of the play/pause button
playpause_color=#FFFFFF
# color of the element when held down (pressed)
held_element_color=#999999
# color of a hovered button when hover_effect includes "color"
hover_effect_color=#FB8C00
# color of the border for thumbnails (with thumbfast)
thumbnail_border_color=#111111
# color of the border outline for thumbnails
thumbnail_border_outline=#404040
# alpha of the OSC background box
fade_alpha=130
# blur strength for the OSC alpha fade. caution: high values can take a lot of CPU time to render
fade_blur_strength=100
# use with "fade_blur_strength=0" to create a transparency box
fade_transparency_strength=0
# alpha of the window title bar (0 to disable)
window_fade_alpha=100
# blur strength for the window title bar. caution: high values can take a lot of CPU time to render
window_fade_blur_strength=100
# use with "window_fade_blur_strength=0" to create a transparency box
window_fade_transparency_strength=0
# width of the thumbnail border (for thumbfast)
thumbnail_border=3
# rounded corner radius for thumbnail border (0 to disable)
thumbnail_border_radius=3
# Button hover effects
# active button hover effects: "glow", "size", "color"; can use multiple separated by commas
hover_effect=size,glow,color
# relative size of a hovered button if "size" effect is active
hover_button_size=115
# glow intensity when "glow" hover effect is active
button_glow_amount=5
# apply hover size effect to slider handle
hover_effect_for_sliders=yes
# Tooltips and hints
# enable tooltips for disabled buttons and elements
tooltips_for_disabled_elements=yes
# enable text hints for info, loop, ontop, and screenshot buttons
tooltip_hints=yes
# Progress bar settings
# size ratio of the seekbar handle (range: 0 ~ 1)
seek_handle_size=0.8
# show seek range overlay
seekrange=yes
# transparency of the seek range
seekrangealpha=150
# update chapter markers on the seekbar when duration changes
livemarkers=yes
# use keyframes when dragging the seekbar
seekbarkeyframes=no
# top chapter nibbles above seekbar
nibbles_top=yes
# bottom chapter nibbles below seekbar
nibbles_bottom=yes
# chapter nibble style. "triangle", "bar" or "single-bar"
nibbles_style=triangle
# automatically set keyframes for the seekbar based on video length
automatickeyframemode=yes
# videos longer than this (in seconds) will have keyframes on the seekbar
automatickeyframelimit=600
# always show a small progress line at the bottom of the screen
persistentprogress=no
# height of the persistent progress bar
persistentprogressheight=17
# show buffer status on web videos in the persistent progress line
persistentbuffer=no
# Miscellaneous settings
# only used at init to set visibility_mode(...)
visibility=auto
# visibility modes to cycle through, modes are separated by _
visibility_modes=never_auto_always
# minimum interval between OSC redraws (in seconds)
tick_delay=0.03
# use display FPS as the minimum redraw interval
tick_delay_follow_display_fps=no
# Elements Position
# Useful when adjusting font size or type
# title height position above seekbar
title_height=96
# title height position if a chapter title is below it
title_with_chapter_height=108
# chapter title height position above seekbar
chapter_title_height=91
# time codes height position
time_codes_height=35
# time codes height position with portrait window
time_codes_centered_height=57
# tooltip height position offset
tooltip_height_offset=2
# if tooltip contains many characters, it is moved to the left by offset
tooltip_left_offset=5
# portrait window width trigger to move some elements
portrait_window_trigger=1000
# hide volume bar trigger window width
hide_volume_bar_trigger=1150
# osc height offset if title above seekbar is disabled
notitle_osc_h_offset=25
# osc height offset if chapter title is disabled or doesn't exist
nochapter_osc_h_offset=10
# seek hover timecodes tooltip height position offset
seek_hover_tooltip_h_offset=0
# osc height without offsets
osc_height=132
## Mouse commands
## details: https://github.com/Samillion/ModernZ#mouse-commands-user-options
# title above seekbar mouse actions
title_mbtn_left_command=script-binding stats/display-page-5
title_mbtn_mid_command=show-text ${path}
title_mbtn_right_command=script-binding select/select-watch-history; script-message-to modernz osc-hide
# playlist button mouse actions
playlist_mbtn_left_command=script-binding select/menu; script-message-to modernz osc-hide
playlist_mbtn_right_command=script-binding select/select-playlist; script-message-to modernz osc-hide
# volume mouse actions
vol_ctrl_mbtn_left_command=no-osd cycle mute
vol_ctrl_mbtn_right_command=script-binding select/select-audio-device; script-message-to modernz osc-hide
vol_ctrl_wheel_down_command=no-osd add volume -5
vol_ctrl_wheel_up_command=no-osd add volume 5
# audio button mouse actions
audio_track_mbtn_left_command=script-binding select/select-aid; script-message-to modernz osc-hide
audio_track_mbtn_mid_command=cycle audio down
audio_track_mbtn_right_command=cycle audio
audio_track_wheel_down_command=cycle audio
audio_track_wheel_up_command=cycle audio down
# subtitle button mouse actions
sub_track_mbtn_left_command=script-binding select/select-sid; script-message-to modernz osc-hide
sub_track_mbtn_mid_command=cycle sub down
sub_track_mbtn_right_command=cycle sub
sub_track_wheel_down_command=cycle sub
sub_track_wheel_up_command=cycle sub down
# chapter skip buttons mouse actions
chapter_prev_mbtn_left_command=add chapter -1
chapter_prev_mbtn_mid_command=show-text ${chapter-list} 3000
chapter_prev_mbtn_right_command=script-binding select/select-chapter; script-message-to modernz osc-hide
chapter_next_mbtn_left_command=add chapter 1
chapter_next_mbtn_mid_command=show-text ${chapter-list} 3000
chapter_next_mbtn_right_command=script-binding select/select-chapter; script-message-to modernz osc-hide
# chapter title (below seekbar) mouse actions
chapter_title_mbtn_left_command=script-binding select/select-chapter; script-message-to modernz osc-hide
chapter_title_mbtn_right_command=show-text ${chapter-list} 3000
# playlist skip buttons mouse actions
playlist_prev_mbtn_left_command=playlist-prev
playlist_prev_mbtn_mid_command=show-text ${playlist} 3000
playlist_prev_mbtn_right_command=script-binding select/select-playlist; script-message-to modernz osc-hide
playlist_next_mbtn_left_command=playlist-next
playlist_next_mbtn_mid_command=show-text ${playlist} 3000
playlist_next_mbtn_right_command=script-binding select/select-playlist; script-message-to modernz osc-hide
# fullscreen button mouse actions
fullscreen_mbtn_left_command=cycle fullscreen
fullscreen_mbtn_right_command=cycle window-maximized
# info button mouse actions
info_mbtn_left_command=script-binding stats/display-page-1-toggle

View File

@@ -1,49 +0,0 @@
# Automatically generate the thumbnails on video load, without a keypress
autogenerate=no
# 1 hour, Only automatically thumbnail videos shorter than this (seconds)
autogenerate_max_duration=3600
# SHA1-sum filenames over this length
# It's nice to know what files the thumbnails are (hence directory names)
# but long URLs may approach filesystem limits.
hash_filename_length=128
# Use mpv to generate thumbnail even if ffmpeg is found in PATH
# ffmpeg does not handle ordered chapters (MKVs which rely on other MKVs)!
# mpv is a bit slower, but has better support overall (eg. subtitles in the previews)
prefer_mpv=yes
# Disable the built-in keybind ("T") to add your own
disable_keybinds=no
# The thumbnail count target
# (This will result in a thumbnail every ~10 seconds for a 25 minute video)
thumbnail_count=150
# The above target count will be adjusted by the minimum and
# maximum time difference between thumbnails.
# The thumbnail_count will be used to calculate a target separation,
# and min/max_delta will be used to constrict it.
# In other words, thumbnails will be:
# at least min_delta seconds apart (limiting the amount)
# at most max_delta seconds apart (raising the amount if needed)
min_delta=5
# 120 seconds aka 2 minutes will add more thumbnails when the video is over 5 hours!
max_delta=90
# Overrides for remote urls (you generally want less thumbnails!)
# Thumbnailing network paths will be done with mpv
# Allow thumbnailing network paths (naive check for "://")
thumbnail_network=no
# Override thumbnail count, min/max delta
remote_thumbnail_count=60
remote_min_delta=15
remote_max_delta=120
# Try to grab the raw stream and disable ytdl for the mpv subcalls
# Much faster than passing the url to ytdl again, but may cause problems with some sites
remote_direct_stream=yes

View File

@@ -1,22 +0,0 @@
# Timestamp
# Display total time instead of remaining time
timetotal=yes
# Display timecodes with milliseconds
timems=no
# Whether to display the chapters/playlist at the OSD when left-clicking the next/previous OSC buttons, respectively.
playlist_osd=yes
chapters_osd=yes
# Duration of fade out in ms, 0 = no fade
fadeduration=200
# Minimum amount of pixels the mouse has to move between ticks to make the OSC show up. Default pre-0.21.0 was 3.
minmousemove=0
# auto=hide/show on mouse move
# Also supports never and always
visibility=auto
# Use a Unicode minus sign instead of an ASCII hyphen when displaying the remaining playback time.
unicodeminus=no

View File

@@ -1,169 +0,0 @@
#### ------- Mpv-Playlistmanager configuration ------- ####
#navigation keybindings force override only while playlist is visible
#if "no" then you can display the playlist by any of the navigation keys
dynamic_binds=yes
# To bind multiple keys separate them by a space
# main key to show playlist
key_showplaylist=SHIFT+ENTER
# display playlist while key is held down
key_peek_at_playlist=
# dynamic keys
key_moveup=UP
key_movedown=DOWN
key_movepageup=PGUP
key_movepagedown=PGDWN
key_movebegin=HOME
key_moveend=END
key_selectfile=RIGHT LEFT
key_unselectfile=
key_playfile=ENTER
key_removefile=BS
key_closeplaylist=ESC SHIFT+ENTER
# extra functionality keys
key_sortplaylist=
key_shuffleplaylist=
key_reverseplaylist=
key_loadfiles=
key_saveplaylist=
#json format for replacing, check .lua for explanation
#example json=[{"ext":{"all":true},"rules":[{"_":" "}]},{"ext":{"mp4":true,"mkv":true},"rules":[{"^(.+)%..+$":"%1"},{"%s*[%[%(].-[%]%)]%s*":""},{"(%w)%.(%w)":"%1 %2"}]},{"protocol":{"http":true,"https":true},"rules":[{"^%a+://w*%.?":""}]}]
#empty for no replace
filename_replace=[{"protocol":{"all":true},"rules":[{"%%(%x%x)":"hex_to_char"}]}]
#filetypes to search from directory
loadfiles_filetypes=["jpg","jpeg","png","tif","tiff","gif","webp","svg","bmp","mp3","wav","ogm","flac","m4a","wma","ogg","opus","mkv","avi","mp4","ogv","webm","rmvb","flv","wmv","mpeg","mpg","m4v","3gp"]
#loadfiles at startup if 1 or more items in playlist
loadfiles_on_start=no
#loadfiles from working directory on idle startup
loadfiles_on_idle_start=no
#always put loaded files after currently playing file
loadfiles_always_append=no
#sort playlist when any files are added to playlist after initial load
sortplaylist_on_file_add=no
#default sorting method, must be one of: "name-asc", "name-desc", "date-asc", "date-desc", "size-asc", "size-desc".
default_sort=name-asc
#linux | windows | auto
system=auto
#Use ~ for home directory. Leave as empty to use mpv/playlists
playlist_savepath=
#constant filename to save playlist as. Note that it will override existing playlist. Leave empty for generated name.
playlist_save_filename=
#save playlist automatically after current file was unloaded
save_playlist_on_file_end=no
#show file title every time a new file is loaded
show_title_on_file_load=no
#show playlist every time a new file is loaded
show_playlist_on_file_load=no
#close playlist when selecting file to play
close_playlist_on_playfile=no
#sync cursor when file is loaded from outside reasons(file-ending, playlist-next shortcut etc.)
sync_cursor_on_load=yes
#allow the playlist cursor to loop from end to start and vice versa
loop_cursor=yes
#allow playlistmanager to write watch later config when navigating between files
allow_write_watch_later_config=yes
#reset cursor navigation when closing or opening playlist
reset_cursor_on_close=yes
reset_cursor_on_open=yes
#prefer to display titles for following files: "all", "url", "none". Sorting still uses filename
prefer_titles=url
#youtube-dl executable for title resolving if enabled, probably "youtube-dl" or "yt-dlp", can be absolute path
youtube_dl_executable=yt-dlp
#call youtube-dl to resolve the titles of urls in the playlist
#if yes, prefer_titles must be set to "url" or "all" for this to work
resolve_url_titles=no
#call ffprobe to resolve the titles of local files in the playlist (if they exist in the metadata)
#if yes, prefer_titles must be set to "all" for this to work
resolve_local_titles=no
#timeout in seconds for url title resolving
resolve_title_timeout=15
#how many url titles can be resolved at a time. Higher number might lead to stutters.
concurrent_title_resolve_limit=10
#osd timeout on inactivity in seconds, use 0 for no timeout
playlist_display_timeout=0
#when peeking at playlist, show playlist at the very least for display timeout
peek_respect_display_timeout=no
#the maximum amount of lines playlist will render. -1 will automatically calculate lines.
showamount=-1
#playlist ass style overrides
#example {\q2\an7\fnUbuntu\fs10\b0\bord1} equals: line-wrap=no, align=top left, font=Ubuntu, size=10, bold=no, border=1
#read http://docs.aegisub.org/3.2/ASS_Tags/ for reference of tags
#undeclared tags will use default osd settings
#these styles will be used for the whole playlist
#\q2 style is recommended since filename wrapping may lead to unexpected rendering
#\an7 style is recommended to align to top left, otherwise osd-align-x/y is respected
style_ass_tags={\q2\an7}
#paddings for left right and top bottom
text_padding_x=30
text_padding_y=60
#screen dim when menu is open 0.0 - 1.0 (0 is no dim, 1 is black)
curtain_opacity=0.7
#set title of window with stripped name
set_title_stripped=no
title_prefix=
title_suffix= - mpv
#slice long filenames, and how many chars to show
slice_longfilenames=no
slice_longfilenames_amount=70
#Playing header. One newline will be added after the string.
#%mediatitle or %filename = title or name of playing file
#%pos = position of playing file
#%cursor = position of navigation
#%plen = playlist lenght
#%N = newline
playlist_header=[%cursor/%plen]
#Playlist file templates
#%pos = position of file with leading zeros
#%name = title or name of file
#%N = newline
#you can also use the ass tags mentioned above. For example:
# selected_file={\c&HFF00FF&}➔ %name | to add a color for selected file. However, if you
# use ass tags you need to reset them for every line (see https://github.com/jonniek/mpv-playlistmanager/issues/20)
normal_file={\c&HEEECE8&}○ %name
hovered_file={\c&H33FFFF&}● %name
selected_file={\c&HFF00FF&}➔ %name
playing_file={\c&H91ff4c&}▷ %name
playing_hovered_file={\c&H00FF00&}▶ %name
playing_selected_file={\c&Hff9ad3&}➤ %name
#what to show when playlist is truncated
playlist_sliced_prefix=...
playlist_sliced_suffix=...
#output visual feedback to OSD when saving, shuffling, reversing playlists
display_osd_feedback=yes

View File

@@ -1,54 +0,0 @@
### Config
showPictureInPictureButton=yes
showSpeedButton=yes
# Show name and shortcut of buttons on hover
showShortcutTooltip=yes
# Show chapter above timestamp in seekbar tooltip
showChapterTooltip=yes
# skipback/skipfrwd amount in seconds
skipBy=5
# RightClick skipback/skipfrwd amount in seconds
skipByMore=30
# "exact" (mordenx default) or "relative+keyframes" (mpv default)
skipMode=exact
# PictureInPicture 33% screen width, 10px from bottom right
pipGeometry=33%+-10+-10
# PictureInPicture will show video on all virtual desktops
pipAllWorkspaces=yes
### Sizes
# 16:9 video thumbnail = 256x144
thumbnailSize=256
seekbarHeight=20
controlsHeight=64
buttonTooltipSize=20
windowBarHeight=44
windowButtonSize=44
windowTitleSize=24
cacheTextSize=20
timecodeSize=27
seekbarTimestampSize=30
seekbarTimestampOutline=1
chapterTickSize=6
windowTitleOutline=1
### Colors (uses GGBBRR for some reason)
### Alpha ranges 0 (opaque) .. 255 (transparent)
textColor=FFFFFF
buttonColor=CCCCCC
buttonHoveredColor=FFFFFF
buttonHoveredRectColor=000000
# Easily debug button geometry by setting buttonHoveredRectAlpha to 80
buttonHoveredRectAlpha=255
tooltipColor=CCCCCC
windowBarColor=000000
# windowBarAlpha (80 is mpv default) (255 morden default)
windowBarAlpha=255
windowButtonColor=CCCCCC
closeButtonHoveredColor=1111DD
seekbarHandleColor=FFFFFF
seekbarFgColor=483DD7
seekbarBgColor=929292
seekbarCacheColor=000000
seekbarCacheAlpha=128
chapterTickColor=CCCCCC

View File

@@ -0,0 +1,17 @@
# This is configuration file for thumbfast.lua
# The default options are listed in thumbfast.lua
# Maximum thumbnail size in pixels (scaled down to fit)
# Values are scaled when hidpi is enabled
max_height=250
max_width=250
# Spawn thumbnailer on file load for faster initial thumbnails
spawn_first=yes
# Enable on network playback
# This allows thumbnailing in videos played over network, e.g. YouTube
network=yes
# Enable hardware decoding
hwdec=yes

View File

@@ -0,0 +1,352 @@
-- various audio visualization
local opts = {
mode = "novideo",
-- off disable visualization
-- noalbumart enable visualization when no albumart and no video
-- novideo enable visualization when no video
-- force always enable visualization
name = "showcqt",
-- off
-- showcqt
-- avectorscope
-- showspectrum
-- showcqtbar
-- showwaves
quality = "medium",
-- verylow
-- low
-- medium
-- high
-- veryhigh
height = 6,
-- [4 .. 12]
forcewindow = true,
-- true (yes) always run visualizer regardless of force-window settings
-- false (no) does not run visualizer when force-window is no
}
-- key bindings
-- cycle visualizer
local cycle_key = "c"
if not (mp.get_property("options/lavfi-complex", "") == "") then
return
end
local visualizer_name_list = {
"off",
"showcqt",
"avectorscope",
"showspectrum",
"showcqtbar",
"showwaves",
}
local axis_0 = "image/png;base64," ..
"iVBORw0KGgoAAAANSUhEUgAAB4AAAAAgCAQAAABZEK0tAAAACXBIWXMAAA7EAAAOxAGVKw4bAAASO0lEQVR42u2de2wU1xXGV/IfSJEqVUJCQrIUISFFiiqhSFWkKFKFokpB1TqxHROT8ApueDgEE9u4MW4TSqFA" ..
"3TSUQmkSChRwII6BkAQCDSYlBtc1hiSA4/CyMcYGtsZvY3t3vXu719vVPjxzz71zd+wBvnOkdvHZ78w5v7mZmbt7Z9blgsFgMBgMBoPBYDAYDAaDwWAwGAwGg8FgMBgMBoPBYDAYDAaDwWCw+9HYBFbKboe8lE1A" ..
"HHHEEUccccQRRxxxxBFHHPEHNe4KBSJWijjiiCOOOOKII4444ogjjjjiD1icwWAwGAwGg8FgMBgM9hAYJsAwGAwGg8FgMBgMBnsozOVyR7zuQOSPdQeif0UcccQRRxxxxBFHHHHEEUcc8QciHn05KaPuwGDHYEfd" ..
"gUkZRgkQRxxxxBFHHHHEEUccccQRR/w+jhu9FQ6Hw+FwOBwOh8Ph8AfOx3Zz07LTXpmYzl89McuJOJ6e/czcCWkP7u4Gf/AHf/AHf/AHf/AHf/AHf/B/iPm73D99qaW2u7n7RqI/8lz4LWbxw1tVNjQh7dgH/Z6R" ..
"JdjBzmuXKxl7b42sdvqctrORCjqvTc1S3elx9V9vOXNy1+gcP3r+5K6Bu7y8YW/jqZO7PPU5S+Tyx/Fp9lysO/CLV1TqA3/wB3/wB3/wB3/wB3/wB3/wB/8x4e9yL37N+PlYP3o+/BazePVe+c089XL7D4n6qjJZ" ..
"dUlhrO7TLWo7wKj+gbvxkGbMv3sl8T3Ht8vlL8hLVPr6dq7Xqw/8wR/8wR/8wR/8wR/8wR/8wR/8k86f/89bK26eYazjSsXGsJ8ui90Bo+MVG7ua1HZAY1VoZj9Utacof8b8DSU15cGAmn5tcfnG/zaE2+tqUtsB" ..
"8fXv33T6w8EOxpprYt9xs46xgK9qT0Hes/M2rbr13cgA2SOfP+hnrLacZ68t72sNiYNvrbBWH/iDP/iDP/iDP/iDP/iDP/iDP/jbxD/8f3UVjF2v5q8ef9HlXpQbyjAcuxY7Gp8y8uV1878ZO7lLtsDNv+Ul/e5X" ..
"0b9cqlT9JGFypq+XscZTHM3bRaq7IFo/9z+/zZivPxrdsY7Xt35l5N8paV3XGavcLp8/4GMs0t+UrFvf8mESWcKgVh/4gz/4gz/4gz/4gz/4gz/4gz/428Q/vsC1xQFf9b5JGXcvf3/UqIE1bw57az5yuff/uadl" ..
"eZ5sefzzh8ZTsX+ZPmfvO5MzVRCWv8tXhz8xi6O5+pXeDqjaw1hvazTaFNqtjV/Hvn/Xho4ruUut7QCXO/vV4DBja95Ur0+Ff+Fy8Ad/8Ad/8Ad/8Ad/8Ad/8Ad/8FfgHy2wt7Wugs+d284aNxCJ36xTbb+7mbGj" ..
"76uq4p2vYb9U6XIf3sq/LH/qZfUdwOuvq/juM89F/nnD3ndi6gvt1C+06ovfAaGMN9Q6Bn/wB3/wB3/wB3/wB3/wB3/wB3/b+UcLjFjbOeMGRPFHnpu7yBzKPQ9jkduSH39xweKcJTlLFiz+Sbas3uVe9jrf8soC" ..
"rh8eZOzETpXtx9cfvgm7IOb76/6Y+sw8Je3Jl+R3AF/TfrpMXq/LX5yf5k/VR/FX6c8K/4npOUvi61XjT+l1+Yvz0/yp+ij+Kv1Z4f/oC4tyfz7POn9Kr8tfnJ/mT9VH8Vfpz9rxR+0EMPr4Q5+g9I4/Ipc5/oid" ..
"Pv7I9wf+9yf/1MxXc/kCQav8Rfpk8DfPL8dfVJ8Mf9n+MP7vv/HPr29/Nts6f0qfjOt/8/xy1/+i+mSu/2X7szb+017JWWK+qJYe/2K9/vgX5ZcZ/+L66PEv35/Djj/RAgfaG6u6Gs0/gTCPry4aaOdtNf/70ReM" ..
"NtJ/i7GyUv6qII/ffv1/Cxbly+ld7otH+Kr469Xcvd2M9d+OXSFP60fqv8vVzdWe+oCXsYA3+hV5/23GPvyjGaKfZB/a0nTK211/VH4H3DkfGiQ75PU6/On8Yv4y9Yn4S/dnkX9KWs1HXMEXUZj9epmIv4xehz+d" ..
"X8xfpj4Rf+n+LPJPzfz+GOfLWOfVuYvU+cvodfjT+cX8ZeoT8ZfuzyL/sJcU+geHB+ctVucvo9c7/lP5qeM/XZ/4+C/Zn0X+0+cEfGEf9n77qTp/Gb0Ofzq/mL9MfSL+0v1pjP8JabUf8wsvFvzkL1bGP6XXHf/i" ..
"/PT4p+qjxr9Ufxb5tzdE9i/3jBxV/jJ6Hf50fjF/mfpE/KX7szz+95R6e3jBd86b/cCLePzTer3xT+Wnxj9dn3j8S/Znmf9rr/e08Pz9HmvnX1qvx5/KT/Gn6xPzl+xP6/pHbQI8+vpHYgLM12i/t4axugMu94aS" ..
"tm8W5cY3wON/X8fYuYOJF6D3PN7ek7svf8VYTbnRRtrOMla1m796Zm74t564+e+FPwWg9VOz/AOJj7revEp++4lr0J98qb2BsfYfIv/mzzerrTBDdO4gX/3OmPwEeELaUGeowt/K63X40/nF/Gm9mL9Kf1b4f7mN" ..
"sdvnj29vrmbBq1+r85fR6/Cn84v503oxf5X+rPCv2MhYS+2xbRePDA92XlPnL6PX4U/nF/On9WL+Kv1Z4R8m2nmNb9Xst/FE/GX0Ovzp/GL+tF7MX6U/K/yfmcsfqXG58nLlD8e3rlbnL6PX4U/nF/On9WL+Kv1Z" ..
"G/+pmfwpop3Xaj769tDqIvXxT+v1xj+Vnxr/lJ4a//L9WeHf3jDQwffu5cq+NsaM17mI+MvodfjT+cX8ab2Yv0p/Vvgvez043Nd6uqzhy4DPU69+/JHR6/Cn84v503oxf5X+rPBPSeu+4R+s3ne6zD8w0G5856yI" ..
"v4xehz+dX8yf1ov5q/Rn9fpHbQI8+vpHegLscucuTQnN7fnTvmK/5o7G85alpI2+AA3jaP5PwBt9eHfUa/kK8JsRNFOypmbxXRJ5DDetP7QltLsG+ArysPe2hi45z8hvP3EHuNzb1jLm7Y386/SHoX/1zJgfjU9M" ..
"L3931sLI7nq7aGK6ygT4c75O3v/MXHm9Dn86v5g/rRfzV+tPnX/bue7m8OdNjaeGBxO/+aH5y+h1+NP5xfxpvZi/Wn/q/KdmrS0Ovzr/GWPGP4Mu4i+j1+FP5xfzp/Vi/mr9qfPnzu+84ZdXchPgeP4yeh3+dH4x" ..
"f1ov5q/Wnzp/PsGjfjJCxF9Gr8Ofzi/mT+vF/NX6szL++c+CfHPI+MgmM/5pvd74p/JT45/SU+NfpT91/sX5kUl1b2t3szp/Gb0Ofzq/mD+tF/NX60+d/4kdjIUnQ98eYsx4kbuIv4xehz+dX8yf1ov5q/Wnzn/m" ..
"Lxk7/eFIH+WM7Vinyl9Gr8Ofzi/mT+vF/NX6s3b9ozYBHn39Q0yAfzabPxb79vmi/Ih7vo89QEfjK94YfaftuU+CgfC0k4My+hJ8xnz/YGjG31BakprJPzFYnsefJRbJT+mfnce/+G89G/ls7cmX6vYzFgwW54eH" ..
"Ar39+P7eWlGx0VPPF0xE4o/N7LvFv9bfUxr+z6cg785Fxm7GXWKJJnjTsgN+xg5uKsovzt/2+4tHWHD0CnSRXo8/nT+Rf96yWP6UnuKv2p8q/6deDt/dMTG9+8Y9jyz/aHe0Xo8/nV/Mn9JT/FX7szb+p8/ZvGqw" ..
"o7NRnT+tT8b4F+WXGf/mernxL9+fOv+nZ/v6Oq9+9Q+zCR7Fn9Lr8qfyU/zFepq/Wn+q/PkEr/1Sc03LmSPvGU8yxPxpvR5/Or+YP6Wn+Kv2p8p/UoZ/sKvx6dkbSqbPkT//RunRej3+dH4xf0pP8Vftz9rxn196" ..
"m91XJ3P8F+mTcfwX5Zc5/pvr5Y7/8v2p8t+6mrHPt05Ie2LWnfP3/qvOn9br8afzi/lTeoq/an+q/GctDH8r63Lvfcf4m0oxf1qvx5/OL+ZP6Sn+qv1ZPf6Yu9zxx3QCnLuUPzR6tEVShOLRdeMsGEicmTediszl" ..
"d65nrLTEaDOfbuFFcbm3h/9oMbfIwUKsX1v8f2XI+CdtM+aH73fkFl7wTG0/vv6IBXwlhdH3FC739ob/7usN5w8Gd/9BboI4a+Fofo1f/zhddoKqy5+egIr5i/WJ/J+dF+Vf+7Fkf0ngPymj5Qxjxz6Q4990amJ6" ..
"4mWKmT45/M3zy/E308vyF/anzX/Lav63oU6jB03I8Bfpk8FflF+Gv7lejj/Rnyb/H44Hg0X5lduNJ3g0f7Fen784P81fpJfhT/anxf+JWSMLxgYHOxJ/rEGOP6XX5U/lp/iL9TR/if60+OcuDV0sXeCXcEG/0ZM9" ..
"Kf6UXpc/lZ/iL9bT/CX6S8L51+Wu/djq8UesT8751zy/3PnXTC97/hX2p8mf32Tm7Q0O+/tXvGGFv1ivz1+cn+Yv0svwJ/vT4p+S1tfq69+/6eRufpc9fxKyGn9Kr8ufyk/xF+tp/hL9JeX4Y+ayxx/TCfC07PAt" ..
"zGY7ID7e70m8zb/pdOwE9I+/Nt5QacmdC1EQnVc/+lOkRLF+1kK+tG3k8rKLD+/JmXevhHfJ8ODx7TLbT+wvGLznaTr12uuJlxEXDocfZcOt7WxkWSM9wZuW3R3NH/T3tzfsKVWZoOryl5kAi/iL9Yn8J2Uk8lft" ..
"zwr/adn8AfDG9wmM5l9WOvo9Ir0+f1F+Gf7mejn+Kv1Z4f/YzENbQtOMQHP16AOLDH+xXp+/KL8Mf3O9HH+V/lT5/6aQBS8cdrnNJngUf1qvx5/KT/EX62n+qv2pj/+y0tKSiekpafVfMBb74C7Z8U/pdce/OD89" ..
"/kV6mfGv1p8q/02r+F+aq/f+6e6lYDD26aFy/Gm9Hn8qP8VfrKf5q/Zn7fqHP6rGeIGvzPFfrE/G9Y95frnrHzO97PWPfH+q/FMz275hbLAj4AsGyt9V50/r9fhT+Sn+Yj3NX7U/9fFflD/QMfLX0DVWzT718U/p" ..
"dce/OD89/kV6mfGv1p/V44+Zyx5/TCfAuv7NoeBw+AHYfAnygsXm73xs5sqCzauK8uO/xpfX626f8tTMksLNqwryjB6QT00wKdfVJyO/MX/n9GfGf/ZCftdBVZnVvLr6ZOU34++U/kTjn/snf9F7Wp+uXje/aPw7" ..
"oT9j/vyjjb62riZ+kmk7a/yMA5Hr6pOX35i/c/qjxn9BHmOf/dV6fl29bn5q/I93f8b8V7zBHzLHX5UUMnZyl2pWXX3y8hvzd05/ovFflK93htHVJyO/aPw7oT9j/l+8z9i2tSlpU7MaqwL+KVmqWXX1yctvzN85" ..
"/ZmP/ylZ61fmLj25m2/JSmZdfXLym49/Z/RHnX9tcf0U+zcxtvEt/up6dcCnfgEy3no5fxAmwPdnf+uKfb1BP/9s76mX/75u7PVOr8/u/qK+Yx1j5p/x2q93en329Hf5q86r3PlPvd08o35809U7vT67+5ucGbnX" ..
"74M1jO3aMNZ6p9dnd39TsoaHum/wVzlLGPvXP8Za7/T67O4v7GcPitZ32K93en329dfwZdCfOvIAoyN/Y8xskbF9eqfXZ3d/EV/zZsDXdV30qDl79U6vz+7+bPJknAAG2oe6jm///hhjdfvvPz3lxfkXDtcfZay7" ..
"pf5obYX02vKk6Z1en739PTuP37PQ1VR/tP6o5yJjks92S5re6fXZ3Z/L3VzdXP351oObqvcNdfv6jX/mwU690+uzu7+wn9jZfinysInx0Du9Pvv662rsaancvn9TzT5vz1D3tOyx1ju9Prv7c7n5mb3hn59u6bjC" ..
"TJcY26l3en1298f9nqf7+njqnV6fff2Vv8t/4urEzu8+8/V7e1Izx1rv9Prs7u/xF2srTuy4+q9gYKizcPnY651en9392ezJSLJ+5VAXX4DdenZq1v2oF3vl9uhN1v7+2Id1j43e6fXZ29/shfF3RryQM7Z6p9dn" ..
"d38ud/W+yL0Zva3rV4693un12d0f9x+n8x+zZ+yeZ1LGeOidXp+d/ZVv9PaE9293i9kdtnbqnV6f3f3x59u3/Cf84JQv3h8PvdPrs7s/l/uR5/pu6Sxu19U7vT57+6v9OHyG6WuL/tTLWOqdXp+9/WXk8AfMMea5" ..
"+ItXxkPv9Prs7s9mT9YpIHepTvvjrYfD4Waempm7tDj/+QVWl7fo6p1en939wcfXH3luweKifLMfmbFf7/T67O6Pe/ary/MefWH89E6vz+7+4OPpU7Pyls38pfXzi67e6fXZ29/kzOV5OrMLXb3T67O7P1sdBxc4" ..
"HA6Hw+FwOBwOhz8UDgRwOBwOh8PhcDgcDn8oHAjgcDgcDofD4XA4HP4w+P8AQEuXMXpD8/kAAAAASUVORK5CYII="
local axis_1 = "image/png;base64," ..
"iVBORw0KGgoAAAANSUhEUgAAB4AAAAAwCAQAAABaxq+2AAAACXBIWXMAAA7EAAAOxAGVKw4bAAATVklEQVR42u2df0xUZ7rHJ+EPkiabbGJiYkLSmJg0aTYxTTZNmiYb09ykZjO0QLHY+quy9Qe1YgG5Re62rlev" ..
"etluXVevt62rrkq1FLG21epW7FqUZRFtq1LqLxAR1FnkNwIzw8x752V27gzDOe/zvuedA0f5fp9kd+SZ7zPv8zlvz5x35pwzLhcEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAE" ..
"QRAEQRAEQRAEQRAEQRAEQRAEQRBkq1gyK2F3Q1HCkpFHHnnkkUceeeSRRx555JFH/lHNu0KJiEqQRx555JFHHnnkkUceeeSRR/4RyzMIgiAIgiAIgiAImgTCAhiCIAiCIAiCIAiaFHK53JGoq4j8sa4i+lfkkUce" ..
"eeSRRx555JFHHnnkkX8k8tGHU9PrKgY7BjvqKqamGxVAHnnkkUceeeSRRx555JFHHvmHOG/0VAQCgUAgEAgEAoFAIB65AAIEAoFAIBAIBAKBQEyKAAIEAoFAIBAIBAKBQEyKGN+Xm5mV+tqUNP7oqblOxPHsvOcW" ..
"JKc+upsb/MEf/MEf/MEf/MEf/MEf/MF/EvN3uX/5Skttd3P3rfh47IXwU8zyR3eovFBy6omP+j0jN+EKdt64WsnYB+tlvbPmt52PjKDzxoxM1Y0+avw3W86d3ju2xs9ePL134D4f3rC38czpvZ767OVy9UfxafZc" ..
"rqv49Wsq4wN/8Ad/8Ad/8Ad/8Ad/8Ad/8Af/ceHvci97w/gXkn72YvgpZvnqA/Iv88yr7T/F+6tKZd3FBbG+z7erbQCj8Q/cHw1p9qL71+Kfc3KXXP383Hinr2/PJr3xgT/4gz/4gz/4gz/4gz/4gz/4g3/C+fP/" ..
"eWf17XOMdVwr3xKOs6WxG2BsvnxLV5PaBmisCq3sh6r2F+bNXrS5uKYsGFDzbygq2/LPhnB7XU1qG2D0+A9tPfvxYAdjzTWxz7hdx1jAV7U/P/f5hVvX3vlhZILsl68f9DNWW8ar15b1tYbMwXdWWxsf+IM/+IM/" ..
"+IM/+IM/+IM/+IM/+NvEP/x/deWM3azmj5582eVemhOqMBx7LnY0P33ky+vmvzN2eq/sALf9jg/pP/89+pcrlaqfJEzL8PUy1niGo3m3UHUTRMfP44/vMubrj2Z3b+Tj27Qm8u+k1K6bjFXukq8f8DEW6W965p3v" ..
"+TSJnMKgNj7wB3/wB3/wB3/wB3/wB3/wB3/wt4n/6AFuKAr4qg9OTb9/9cfjRg2sf3vYW/OJy33ojz0tq3Jlh8c/f2g8E/uXWfMPvDctQwVh2fv87PCn5nI017/R2wBV+xnrbY1mm0KbtfHb2Ofv3dxxLWeFtQ3g" ..
"cme9HhxmbP3b6uNT4V+wCvzBH/zBH/zBH/zBH/zBH/zBH/wV+EcH2NtaV87Xzm3njRuI5G/Xqbbf3czY8Q9VXaODn8N+pdLlPrqDf1n+zKvqG4CPv678hy88l/nnDQfeixlfaKN+pTW+0RsgVPGWWsfgD/7gD/7g" ..
"D/7gD/7gD/7gD/7gbzv/6AAjartg3IAo/9gLC5aaQ3ngYSxyWfKTLy9elr08e/niZb/IkvW73Cvf5K+8Jp/7hwcZO7VH5fVHjz98EXZ+zPfX/THjM4uk1Kdfkd8A/Jz2s6Xyfl3+4vo0f2p8FH+V/qzwn5KWvXz0" ..
"eNX4U35d/uL6NH9qfBR/lf6s8H/8paU5/7bQOn/Kr8tfXJ/mT42P4q/Sn7X9j9obwNj9D/0Gpbf/EYXM/kcc9P5Hvj/wfzj5p2S8nsNPELTKX+RPBH/z+nL8ReOT4S/bH+b/wzf/+fHtr+ZZ50/5E3H8b15f7vhf" ..
"ND6Z43/Z/qzN/9TXspebn1RLz3+xX3/+i+rLzH/x+Oj5L9+fw/Y/0QEOtDdWdTWafwJhnl9XONDO22r+++MvGb1I/x3GSkv4o/xcfvn1vxQszJPzu9yXj/Gz4m9W8/B2M9Z/N/YMedo/Mv773N1c7akPeBkLeKNf" ..
"kfffZezj35sh+kXWke1NZ7zd9cflN8C9i6FJslver8Ofri/mLzM+EX/p/izyT0qt+YQ7+EkUZr9eJuIv49fhT9cX85cZn4i/dH8W+adk/HiC82Ws8/qCper8Zfw6/On6Yv4y4xPxl+7PIv9wFBf4B4cHFy5T5y/j" ..
"19v/U/Wp/T89PvH+X7I/i/xnzQ/4wjHs/f5zdf4yfh3+dH0xf5nxifhL96cx/5NTaz/lB14s+NmfrMx/yq87/8X16flPjY+a/1L9WeTf3hDZvjzSs1X5y/h1+NP1xfxlxifiL92f5fm/v8Tbwwd876LZD7yI5z/t" ..
"15v/VH1q/tPjE89/yf4s83/jzZ4WXr/fY+39l/br8afqU/zp8Yn5S/andfyjtgAee/wjsQDm52h/sJ6xugqXe3Nx23dLc0Y3wPN/3sjYhcPxB6APPN7e0/uufsNYTZnRi7SdZ6xqH3/03ILwbz1x+R+EPwWg/TMy" ..
"/QPxt7retlb+9ePPQX/6lfYGxtp/ivyb39+sttwM0YXD/Ox3xuQXwMmpQ52hEf5O3q/Dn64v5k/7xfxV+rPC/+udjN29eHJXczULXv9Wnb+MX4c/XV/Mn/aL+av0Z4V/+RbGWmpP7Lx8bHiw84Y6fxm/Dn+6vpg/" ..
"7RfzV+nPCv8w0c4b/FXNfhtPxF/Gr8Ofri/mT/vF/FX6s8L/uQX8lhpXK69W/nRyxzp1/jJ+Hf50fTF/2i/mr9KftfmfksHvItp5o+aT74+sK1Sf/7Rfb/5T9an5T/mp+S/fnxX+7Q0DHXzrXq3sa2PM+DwXEX8Z" ..
"vw5/ur6YP+0X81fpzwr/lW8Gh/taz5Y2fB3weerV9z8yfh3+dH0xf9ov5q/SnxX+Sandt/yD1QfPlvoHBtqNr5wV8Zfx6/Cn64v5034xf5X+rB7/qC2Axx7/SC+AXe6cFUmhtT2/21fs19zRfO7KpNSxB6BhHM3/" ..
"CHijN++ORi0/A/x2BM30zBmZfJNEbsNN+49sD22uAX4GeTh6W0OHnOfkXz9+A7jcOzcw5u2N/Ovsx6F/9cxeFM1PSSt7f+6SyOZ6t3BKmsoC+Et+nrz/uQXyfh3+dH0xf9ov5q/Wnzr/tgvdzeHPmxrPDA/Gf/ND" ..
"85fx6/Cn64v5034xf7X+1PnPyNxQFH508QvGjH8GXcRfxq/Dn64v5k/7xfzV+lPnz4NfecMPr+QWwKP5y/h1+NP1xfxpv5i/Wn/q/PkCj/rJCBF/Gb8Of7q+mD/tF/NX68/K/Oc/C/LdEeM9m8z8p/1685+qT81/" ..
"yk/Nf5X+1PkX5UUW1b2t3c3q/GX8Ovzp+mL+tF/MX60/df6ndjMWXgx9f4Qx45PcRfxl/Dr86fpi/rRfzF+tP3X+c37D2NmPR/ooY2z3RlX+Mn4d/nR9MX/aL+av1p+14x+1BfDY4x9iAfyrefy22HcvFuZFwvNj" ..
"7A46ml/91tgrbS98FgyEl50clNGX4LMX+QdDK/6GkuKUDP6Jwapcfi+xSH3K//xC/sV/6/nIZ2tPv1J3iLFgsCgvPBXo1x/d3zury7d46vkJE5H8E3P67vCv9feXhP/zyc+9d5mx26MOsUQLvJlZAT9jh7cW5hXl" ..
"7fyvy8dYcOwZ6CK/Hn+6fjz/3JWx/Ck/xV+1P1X+z7wavrpjSlr3rQceWf7R7mi/Hn+6vpg/5af4q/Znbf7Pmr9t7WBHZ6M6f9qfiPkvqi8z/839cvNfvj91/s/O8/V1Xv/mL2YLPIo/5dflT9Wn+Iv9NH+1/lT5" ..
"8wVe+5XmmpZzxz4wXmSI+dN+Pf50fTF/yk/xV+1Plf/UdP9gV+Oz8zYXz5ov//4bpUf79fjT9cX8KT/FX7U/a/t/fuhtdl2dzP5f5E/E/l9UX2b/b+6X2//L96fKf8c6xr7ckZz61Nx7Fx/8U50/7dfjT9cX86f8" ..
"FH/V/lT5z10S/lbW5T7wnvE3lWL+tF+PP11fzJ/yU/xV+7O6/zEPuf2P6QI4ZwW/afRYRUqE8tHzxlkwEL8ybzoTWcvv2cRYSbHRy3y+nQ+K2709/EeLuSI7C7F/Q9G/nCHxT9pmLwpf78gVPuGZev3R448o4Csu" ..
"iD6nYJW3N/x3X2+4fjC477/lFohzl4zl1/jtz9NkF6i6/OkFqJi/2B/P//mFUf61n0r2lwD+U9NbzjF24iM5/k1npqTFH6aY+RPD37y+HH8zvyx/YX/a/Lev438b6jS60YQMf5E/EfxF9WX4m/vl+BP9afL/6WQw" ..
"WJhXuct4gUfzF/v1+Yvr0/xFfhn+ZH9a/J+aO3LC2OBgR/yPNcjxp/y6/Kn6FH+xn+Yv0Z8W/5wVoYOlS/wQLug3urMnxZ/y6/Kn6lP8xX6av0R/CXj/dblrP7W6/xH7E/P+a15f7v3XzC/7/ivsT5M/v8jM2xsc" ..
"9vevfssKf7Ffn7+4Ps1f5JfhT/anxT8pta/V139o6+l9/Cp7fidkNf6UX5c/VZ/iL/bT/CX6S8j+xyxk9z+mC+CZWeFLmM02wOh8vyf+Mv+ms7EL0N//h/ELlRTfuxQF0Xn9kz9Ehij2z13CT20bObzs4tN7Wsb9" ..
"a+FNMjx4cpfM68f3Fww+8DSdeePN+MOIS0fDt7LhajsfOa2RXuDNzOqO1g/6+9sb9peoLFB1+cssgEX8xf54/lPT4/mr9meF/8wsfgN44+sExvIvLRn7HJFfn7+ovgx/c78cf5X+rPB/Ys6R7aFlRqC5euyORYa/" ..
"2K/PX1Rfhr+5X46/Sn+q/H9bwIKXjrrcZgs8ij/t1+NP1af4i/00f9X+1Od/aUlJ8ZS0pNT6rxiLvXGX7Pyn/LrzX1yfnv8iv8z8V+tPlf/WtfwvzdUH/nD/SjAYe/dQOf60X48/VZ/iL/bT/FX7s3b8w29VY3yC" ..
"r8z+X+xPxPGPeX254x8zv+zxj3x/qvxTMtq+Y2ywI+ALBsreV+dP+/X4U/Up/mI/zV+1P/X5X5g30DHy19AxVs1B9flP+XXnv7g+Pf9Ffpn5r9af1f2PWcjuf0wXwLrx3ZHgcPgG2PwU5MXLzJ/5xJw1+dvWFuaN" ..
"/hpf3q/7+lSkZBQXbFubn2t0g3xqgUmFrj8R9Y35O6c/M/7zlvCrDqpKrdbV9Seqvhl/p/Qnmv88PvuT3t36dP269UXz3wn9GfPnH230tXU18TeZtvPG9zgQha4/cfWN+TunP2r+5+cy9sX/WK+v69etT83/ie7P" ..
"mP/qt/hN5vij4gLGTu9VrarrT1x9Y/7O6U80/wvz9N5hdP2JqC+a/07oz5j/Vx8ytnNDUuqMzMaqgH96pmpVXX/i6hvzd05/5vN/euamNTkrTu/jr2Slsq4/MfXN578z+qPef20J/RKHtjK25R3+6GZ1wKd+ADLR" ..
"frl4FBbAD2d/G4t8vUE//2zvmVf/vHH8/U4fn939RWP3RsbMP+O13+/08dnT39VvOq/z4D/1dvuc+v5N1+/08dnd37SMyLV+H61nbO/m8fY7fXx29zc9c3io+xZ/lL2csb/9Zbz9Th+f3f2F4/xh0fkd9vudPj77" ..
"+mv4OuhPGbmB0bH/ZczsJGP7/E4fn939RWL92wFf103Rrebs9Tt9fHb3Z1Mk4g1goH2o6+SuH08wVnfo4fNTUZR36Wj9cca6W+qP15ZLn1ueML/Tx2dvf88v5NcsdDXVH68/7rnMmOS93RLmd/r47O7P5W6ubq7+" ..
"csfhrdUHh7p9/cY/82Cn3+njs7u/cJza034lcrOJifA7fXz29dfV2NNSuevQ1pqD3p6h7plZ4+13+vjs7s/l5u/sDX/9fHvHNWZ6irGdfqePz+7+eDzwdN+cSL/Tx2dff2Xv85+4OrXnhy98/d6elIzx9jt9fHb3" ..
"9+TLteWndl//WzAw1Fmwavz9Th+f3f3ZHIkosmnNUBc/Abv1/IzMh9Evjspd0Yus/f2xN+seH7/Tx2dvf/OWjL4y4qXs8fU7fXx29+dyVx+MXJvR27ppzfj7nT4+u/vj8fM0/mP2jD3wTE2fCL/Tx2dnf2VbvD3h" ..
"7dvdYnaFrZ1+p4/P7v74/e1b/hG+ccpXH06E3+njs7s/l/uxF/ru6Jzcrut3+vjs7a/20/A7TF9b9KdextPv9PHZ2196Nr/BHGOey79+bSL8Th+f3f3ZHIl6C8hZodP+RPsRCIRZpGTkrCjKe3Gx1dNbdP1OH5/d" ..
"/SEmNh57YfGywjyzH5mx3+/08dndH4+s11flPv7SxPmdPj67+0NMZMzIzF055zfW3190/U4fn739TctYlauzutD1O318dvdna2DngkAgEAgEAoFAIBCISRFAgEAgEAgEAoFAIBCISRHRh1PT6yqGOoc66yqMr6NC" ..
"HnnkkUceeeSRRx555JFHHvmHOB99WFcRuZGO8b00kUceeeSRRx555JFHHnnkkUf+Ic4zCIIgCIIgCIIgCJoEwgIYgiAIgiAIgiAImhRyRcVK/v+vJS4DIY888sgjjzzyyCOPPPLII4/8o5B3seTQU+6EooQlI488" ..
"8sgjjzzyyCOPPPLII4/8o5qHIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCEqf/A/SNfayCCBqGAAAAAElFTkSuQmCC"
local options = require 'mp.options'
local msg = require 'mp.msg'
options.read_options(opts)
opts.height = math.min(12, math.max(4, opts.height))
opts.height = math.floor(opts.height)
if not opts.forcewindow and mp.get_property('force-window') == "no" then
return
end
local function get_visualizer(name, quality, vtrack)
local w, h, fps
if quality == "verylow" then
w = 640
fps = 30
elseif quality == "low" then
w = 960
fps = 30
elseif quality == "medium" then
w = 1280
fps = 60
elseif quality == "high" then
w = 1920
fps = 60
elseif quality == "veryhigh" then
w = 2560
fps = 60
else
msg.log("error", "invalid quality")
return ""
end
h = w * opts.height / 16
if name == "showcqt" then
local count = math.ceil(w * 180 / 1920 / fps)
return "[aid1] asplit [ao]," ..
"aformat = channel_layouts = stereo," ..
"firequalizer =" ..
"gain = '1.4884e8 * f*f*f / (f*f + 424.36) / (f*f + 1.4884e8) / sqrt(f*f + 25122.25)':" ..
"scale = linlin:" ..
"wfunc = tukey:" ..
"zero_phase = on:" ..
"fft2 = on," ..
"showcqt =" ..
"fps =" .. fps .. ":" ..
"size =" .. w .. "x" .. h .. ":" ..
"count =" .. count .. ":" ..
"csp = bt709:" ..
"bar_g = 2:" ..
"sono_g = 4:" ..
"bar_v = 9:" ..
"sono_v = 17:" ..
"axisfile = data\\\\:'" .. axis_0 .. "':" ..
"font = 'Nimbus Mono L,Courier New,mono|bold':" ..
"fontcolor = 'st(0, (midi(f)-53.5)/12); st(1, 0.5 - 0.5 * cos(PI*ld(0))); r(1-ld(1)) + b(ld(1))':" ..
"tc = 0.33:" ..
"attack = 0.033:" ..
"tlength = 'st(0,0.17); 384*tc / (384 / ld(0) + tc*f /(1-ld(0))) + 384*tc / (tc*f / ld(0) + 384 /(1-ld(0)))'," ..
"format = yuv420p [vo]"
elseif name == "avectorscope" then
return "[aid1] asplit [ao]," ..
"aformat =" ..
"sample_rates = 192000," ..
"avectorscope =" ..
"size =" .. w .. "x" .. h .. ":" ..
"r =" .. fps .. "," ..
"format = rgb0 [vo]"
elseif name == "showspectrum" then
return "[aid1] asplit [ao]," ..
"showspectrum =" ..
"size =" .. w .. "x" .. h .. ":" ..
"win_func = blackman [vo]"
elseif name == "showcqtbar" then
local axis_h = math.ceil(w * 12 / 1920) * 4
return "[aid1] asplit [ao]," ..
"aformat = channel_layouts = stereo," ..
"firequalizer =" ..
"gain = '1.4884e8 * f*f*f / (f*f + 424.36) / (f*f + 1.4884e8) / sqrt(f*f + 25122.25)':" ..
"scale = linlin:" ..
"wfunc = tukey:" ..
"zero_phase = on:" ..
"fft2 = on," ..
"showcqt =" ..
"fps =" .. fps .. ":" ..
"size =" .. w .. "x" .. (h + axis_h)/2 .. ":" ..
"count = 1:" ..
"csp = bt709:" ..
"bar_g = 2:" ..
"sono_g = 4:" ..
"bar_v = 9:" ..
"sono_v = 17:" ..
"sono_h = 0:" ..
"axisfile = data\\\\:'" .. axis_1 .. "':" ..
"axis_h =" .. axis_h .. ":" ..
"font = 'Nimbus Mono L,Courier New,mono|bold':" ..
"fontcolor = 'st(0, (midi(f)-53.5)/12); st(1, 0.5 - 0.5 * cos(PI*ld(0))); r(1-ld(1)) + b(ld(1))':" ..
"tc = 0.33:" ..
"attack = 0.033:" ..
"tlength = 'st(0,0.17); 384*tc / (384 / ld(0) + tc*f /(1-ld(0))) + 384*tc / (tc*f / ld(0) + 384 /(1-ld(0)))'," ..
"format = yuv420p," ..
"split [v0]," ..
"crop =" ..
"h =" .. (h - axis_h)/2 .. ":" ..
"y = 0," ..
"vflip [v1];" ..
"[v0][v1] vstack [vo]"
elseif name == "showwaves" then
return "[aid1] asplit [ao]," ..
"showwaves =" ..
"size =" .. w .. "x" .. h .. ":" ..
"r =" .. fps .. ":" ..
"mode = p2p," ..
"format = rgb0 [vo]"
elseif name == "off" then
local hasvideo = false
for id, track in ipairs(mp.get_property_native("track-list")) do
if track.type == "video" then
hasvideo = true
break
end
end
if hasvideo then
return "[aid1] asetpts=PTS [ao]; [vid1] setpts=PTS [vo]"
else
return "[aid1] asetpts=PTS [ao];" ..
"color =" ..
"c = Black:" ..
"s =" .. w .. "x" .. h .. "," ..
"format = yuv420p [vo]"
end
end
msg.log("error", "invalid visualizer name")
return ""
end
local function select_visualizer(vtrack)
if opts.mode == "off" then
return ""
elseif opts.mode == "force" then
return get_visualizer(opts.name, opts.quality, vtrack)
elseif opts.mode == "noalbumart" then
if vtrack == nil then
return get_visualizer(opts.name, opts.quality, vtrack)
end
return ""
elseif opts.mode == "novideo" then
if vtrack == nil or vtrack.albumart then
return get_visualizer(opts.name, opts.quality, vtrack)
end
return ""
end
msg.log("error", "invalid mode")
return ""
end
local function visualizer_hook()
local count = mp.get_property_number("track-list/count", -1)
if count <= 0 then
return
end
local atrack = mp.get_property_native("current-tracks/audio")
local vtrack = mp.get_property_native("current-tracks/video")
--no tracks selected (yet)
if atrack == nil and vtrack == nil then
for id, track in ipairs(mp.get_property_native("track-list")) do
if track.type == "video" and (vtrack == nil or vtrack.albumart == true) and mp.get_property("vid") ~= "no" then
vtrack = track
elseif track.type == "audio" then
atrack = track
end
end
end
local lavfi = select_visualizer(vtrack)
--prevent endless loop
if lavfi ~= mp.get_property("options/lavfi-complex", "") then
mp.set_property("options/lavfi-complex", lavfi)
end
end
mp.add_hook("on_preloaded", 50, visualizer_hook)
mp.observe_property("current-tracks/audio", "native", visualizer_hook)
mp.observe_property("current-tracks/video", "native", visualizer_hook)
local function cycle_visualizer()
local i, index = 1
for i = 1, #visualizer_name_list do
if (visualizer_name_list[i] == opts.name) then
index = i + 1
if index > #visualizer_name_list then
index = 1
end
break
end
end
opts.name = visualizer_name_list[index]
visualizer_hook()
end
mp.add_key_binding(cycle_key, "cycle-visualizer", cycle_visualizer)

View File

@@ -1,186 +0,0 @@
local utils = require 'mp.utils'
-- 参数设置
local audioTracksPerPage = 10
local closeAfterLoad = true
local rate = 1.5
-- 全局变量和实用函数
local styleOn = mp.get_property("osd-ass-cc/0")
local audioTracks = {}
local currentSlot = 1
local currentPage = 1
local maxPage = 1
local active = false
-- 控制列表
local audioTrackControls = {
ESC = function() abort("") end,
e = function() abort("") end,
DOWN = function() jumpSlot(1) end,
UP = function() jumpSlot(-1) end,
j = function() jumpSlot(1) end,
k = function() jumpSlot(-1) end,
RIGHT = function() jumpPage(1) end,
LEFT = function() jumpPage(-1) end,
ENTER = function() loadAudioTrack(currentSlot) end,
KP_ENTER = function() loadAudioTrack(currentSlot) end
}
local audioTrackFlags = {
DOWN = {repeatable = true},
UP = {repeatable = true},
RIGHT = {repeatable = true},
LEFT = {repeatable = true}
}
-- 激活自定义控件
function activateControls(name, controls, flags)
for key, func in pairs(controls) do
mp.add_forced_key_binding(key, name..key, func, flags[key])
end
end
-- 取消激活自定义控件
function deactivateControls(name, controls)
for key, _ in pairs(controls) do
mp.remove_key_binding(name..key)
end
end
-- 加载音轨列表
function listAudioTracks()
audioTracks = {}
local tracks = mp.get_property_native("track-list")
for _, track in ipairs(tracks) do
if track.type == "audio" then
table.insert(audioTracks, track)
end
end
calcPages()
end
-- 计算当前页和总页数
function calcPages()
currentPage = math.floor((currentSlot - 1) / audioTracksPerPage) + 1
if currentPage == 0 then currentPage = 1 end
maxPage = math.floor((#audioTracks - 1) / audioTracksPerPage) + 1
if maxPage == 0 then maxPage = 1 end
end
-- 获取指定页的音轨数量
function getAmountAudioTracksOnPage(page)
local n = audioTracksPerPage
if page == maxPage then n = #audioTracks % audioTracksPerPage end
if n == 0 then n = audioTracksPerPage end
if #audioTracks == 0 then n = 0 end
return n
end
-- 获取指定页的第一个音轨索引
function getFirstSlotOnPage(page)
return (page - 1) * audioTracksPerPage + 1
end
-- 获取指定页的最后一个音轨索引
function getLastSlotOnPage(page)
local endSlot = getFirstSlotOnPage(page) + getAmountAudioTracksOnPage(page) - 1
if endSlot > #audioTracks then endSlot = #audioTracks end
return endSlot
end
-- 跳到指定数量的音轨前或后
function jumpSlot(i)
currentSlot = currentSlot + i
local startSlot = getFirstSlotOnPage(currentPage)
local endSlot = getLastSlotOnPage(currentPage)
if currentSlot < startSlot then currentSlot = endSlot end
if currentSlot > endSlot then currentSlot = startSlot end
displayAudioTracks()
end
-- 跳到指定数量的页前或后
function jumpPage(i)
local oldPos = currentSlot - getFirstSlotOnPage(currentPage) + 1
currentPage = currentPage + i
if currentPage < 1 then currentPage = maxPage + currentPage end
if currentPage > maxPage then currentPage = currentPage - maxPage end
local audioTracksOnPage = getAmountAudioTracksOnPage(currentPage)
if oldPos > audioTracksOnPage then oldPos = audioTracksOnPage end
currentSlot = getFirstSlotOnPage(currentPage) + oldPos - 1
displayAudioTracks()
end
-- 显示当前页的音轨
function displayAudioTracks()
-- 确定当前页的第一个和最后一个音轨索引
local startSlot = getFirstSlotOnPage(currentPage)
local endSlot = getLastSlotOnPage(currentPage)
-- 准备显示的文本并显示
local display = styleOn .. "{\\b1}Audio Tracks page " .. currentPage .. "/" .. maxPage .. ":{\\b0}"
for i = startSlot, endSlot do
local track = audioTracks[i]
if (track.title or track.lang or track.src) == nil then
goto nextSlot
end
local selection = ""
if i == currentSlot then
selection = "{\\b1}{\\c&H00FFFF&}>"
end
display = display .. "\n" .. selection .. i .. ": " .. (track.title or track.lang or track.src) .. "{\\r}"
::nextSlot::
end
mp.osd_message(display, rate)
end
-- 加载指定的音轨
function loadAudioTrack(slot)
if slot >= 1 and slot <= #audioTracks then
local track = audioTracks[slot]
if (track.title or track.lang or track.src) == nil then
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the audio track at slot " .. slot)
return
end
mp.set_property_native("aid", track.id)
mp.osd_message(string.format("Loaded audio track: %s", track.title or track.lang or track.src), 2)
if closeAfterLoad then
abort(styleOn.."{\\c&H00FF00&}{\\b1}Successfully loaded audio track:{\\r}\n"..(track.title or track.lang or track.src))
end
else
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the audio track at slot " .. slot)
end
end
-- 定时器
local timer = mp.add_periodic_timer(rate * 0.95, displayAudioTracks)
timer:kill()
-- 终止程序
function abort(message)
mode = "none"
deactivateControls("audio", audioTrackControls)
timer:kill()
mp.osd_message(message)
active = false
end
-- 处理音轨菜单的状态
function handler()
if active then
abort("")
else
activateControls("audio", audioTrackControls, audioTrackFlags)
listAudioTracks()
displayAudioTracks()
timer:resume()
active = true
end
end
-- 注册脚本消息
mp.register_script_message("audio-menu", handler)

View File

@@ -1,5 +1,5 @@
-- This script automatically loads playlist entries before and after the -- This script automatically loads playlist entries before and after the
-- currently played file. It does so by scanning the directory a file is -- the currently played file. It does so by scanning the directory a file is
-- located in when starting playback. It sorts the directory entries -- located in when starting playback. It sorts the directory entries
-- alphabetically, and adds entries before and after the current file to -- alphabetically, and adds entries before and after the current file to
-- the internal playlist. (It stops if it would add an already existing -- the internal playlist. (It stops if it would add an already existing
@@ -10,201 +10,94 @@
To configure this script use file autoload.conf in directory script-opts (the "script-opts" To configure this script use file autoload.conf in directory script-opts (the "script-opts"
directory must be in the mpv configuration directory, typically ~/.config/mpv/). directory must be in the mpv configuration directory, typically ~/.config/mpv/).
Option `ignore_patterns` is a comma-separated list of patterns (see lua.org/pil/20.2.html).
Additionally to the standard lua patterns, you can also escape commas with `%`,
for example, the option `bak%,x%,,another` will be resolved as patterns `bak,x,` and `another`.
But it does not mean you need to escape all lua patterns twice,
so the option `bak%%,%.mp4,` will be resolved as two patterns `bak%%` and `%.mp4`.
Example configuration would be: Example configuration would be:
disabled=no disabled=no
images=no images=no
videos=yes videos=yes
audio=yes audio=yes
additional_image_exts=list,of,ext
additional_video_exts=list,of,ext
additional_audio_exts=list,of,ext
ignore_hidden=yes ignore_hidden=yes
same_type=yes
directory_mode=recursive
ignore_patterns=^~,^bak-,%.bak$
--]] --]]
local MAX_ENTRIES = 5000 MAXENTRIES = 5000
local MAX_DIR_STACK = 20
local msg = require 'mp.msg' local msg = require 'mp.msg'
local options = require 'mp.options' local options = require 'mp.options'
local utils = require 'mp.utils' local utils = require 'mp.utils'
local o = { o = {
disabled = false, disabled = false,
images = true, images = true,
videos = true, videos = true,
audio = true, audio = true,
additional_image_exts = "", ignore_hidden = true
additional_video_exts = "",
additional_audio_exts = "",
ignore_hidden = true,
same_type = false,
directory_mode = "auto",
ignore_patterns = ""
} }
options.read_options(o)
local function Set(t) function Set (t)
local set = {} local set = {}
for _, v in pairs(t) do set[v] = true end for _, v in pairs(t) do set[v] = true end
return set return set
end end
local EXTENSIONS_VIDEO_DEFAULT = Set { function SetUnion (a,b)
local res = {}
for k in pairs(a) do res[k] = true end
for k in pairs(b) do res[k] = true end
return res
end
EXTENSIONS_VIDEO = Set {
'3g2', '3gp', 'avi', 'flv', 'm2ts', 'm4v', 'mj2', 'mkv', 'mov', '3g2', '3gp', 'avi', 'flv', 'm2ts', 'm4v', 'mj2', 'mkv', 'mov',
'mp4', 'mpeg', 'mpg', 'ogv', 'rmvb', 'webm', 'wmv', 'y4m' 'mp4', 'mpeg', 'mpg', 'ogv', 'rmvb', 'webm', 'wmv', 'y4m'
} }
local EXTENSIONS_AUDIO_DEFAULT = Set { EXTENSIONS_AUDIO = Set {
'aiff', 'ape', 'au', 'flac', 'm4a', 'mka', 'mp3', 'oga', 'ogg', 'aiff', 'ape', 'au', 'flac', 'm4a', 'mka', 'mp3', 'oga', 'ogg',
'ogm', 'opus', 'wav', 'wma' 'ogm', 'opus', 'wav', 'wma'
} }
local EXTENSIONS_IMAGES_DEFAULT = Set { EXTENSIONS_IMAGES = Set {
'avif', 'bmp', 'gif', 'j2k', 'jp2', 'jpeg', 'jpg', 'jxl', 'png', 'avif', 'bmp', 'gif', 'j2k', 'jp2', 'jpeg', 'jpg', 'jxl', 'png',
'svg', 'tga', 'tif', 'tiff', 'webp' 'svg', 'tga', 'tif', 'tiff', 'webp'
} }
local EXTENSIONS, EXTENSIONS_VIDEO, EXTENSIONS_AUDIO, EXTENSIONS_IMAGES EXTENSIONS = Set {}
if o.videos then EXTENSIONS = SetUnion(EXTENSIONS, EXTENSIONS_VIDEO) end
if o.audio then EXTENSIONS = SetUnion(EXTENSIONS, EXTENSIONS_AUDIO) end
if o.images then EXTENSIONS = SetUnion(EXTENSIONS, EXTENSIONS_IMAGES) end
local function SetUnion(a, b) function add_files_at(index, files)
for k in pairs(b) do a[k] = true end index = index - 1
return a
end
-- Returns first and last positions in string or past-to-end indices
local function FindOrPastTheEnd(string, pattern, start_at)
local pos1, pos2 = string:find(pattern, start_at)
return pos1 or #string + 1,
pos2 or #string + 1
end
local function Split(list)
local set = {}
local item_pos = 1
local item = ""
while item_pos <= #list do
local pos1, pos2 = FindOrPastTheEnd(list, "%%*,", item_pos)
local pattern_length = pos2 - pos1
local is_comma_escaped = pattern_length % 2
local pos_before_escape = pos1 - 1
local item_escape_count = pattern_length - is_comma_escaped
item = item .. string.sub(list, item_pos, pos_before_escape + item_escape_count)
if is_comma_escaped == 1 then
item = item .. ","
else
set[item] = true
item = ""
end
item_pos = pos2 + 1
end
set[item] = true
-- exclude empty items
set[""] = nil
return set
end
local function split_option_exts(video, audio, image)
if video then o.additional_video_exts = Split(o.additional_video_exts) end
if audio then o.additional_audio_exts = Split(o.additional_audio_exts) end
if image then o.additional_image_exts = Split(o.additional_image_exts) end
end
local function split_patterns()
o.ignore_patterns = Split(o.ignore_patterns)
end
local function create_extensions()
EXTENSIONS = {}
EXTENSIONS_VIDEO = {}
EXTENSIONS_AUDIO = {}
EXTENSIONS_IMAGES = {}
if o.videos then
SetUnion(SetUnion(EXTENSIONS_VIDEO, EXTENSIONS_VIDEO_DEFAULT), o.additional_video_exts)
SetUnion(EXTENSIONS, EXTENSIONS_VIDEO)
end
if o.audio then
SetUnion(SetUnion(EXTENSIONS_AUDIO, EXTENSIONS_AUDIO_DEFAULT), o.additional_audio_exts)
SetUnion(EXTENSIONS, EXTENSIONS_AUDIO)
end
if o.images then
SetUnion(SetUnion(EXTENSIONS_IMAGES, EXTENSIONS_IMAGES_DEFAULT), o.additional_image_exts)
SetUnion(EXTENSIONS, EXTENSIONS_IMAGES)
end
end
local function validate_directory_mode()
if o.directory_mode ~= "recursive" and o.directory_mode ~= "lazy"
and o.directory_mode ~= "ignore" then
o.directory_mode = nil
end
end
options.read_options(o, nil, function(list)
split_option_exts(list.additional_video_exts, list.additional_audio_exts,
list.additional_image_exts)
if list.videos or list.additional_video_exts or
list.audio or list.additional_audio_exts or
list.images or list.additional_image_exts then
create_extensions()
end
if list.directory_mode then
validate_directory_mode()
end
if list.ignore_patterns then
split_patterns()
end
end)
split_option_exts(true, true, true)
split_patterns()
create_extensions()
validate_directory_mode()
local function add_files(files)
local oldcount = mp.get_property_number("playlist-count", 1) local oldcount = mp.get_property_number("playlist-count", 1)
for i = 1, #files do for i = 1, #files do
mp.commandv("loadfile", files[i][1], "append") mp.commandv("loadfile", files[i], "append")
mp.commandv("playlist-move", oldcount + i - 1, files[i][2]) mp.commandv("playlist-move", oldcount + i - 1, index + i - 1)
end end
end end
local function get_extension(path) function get_extension(path)
return path:match("%.([^%.]+)$") or "nomatch" match = string.match(path, "%.([^%.]+)$" )
if match == nil then
return "nomatch"
else
return match
end
end end
local function is_ignored(file) table.filter = function(t, iter)
for pattern in pairs(o.ignore_patterns) do for i = #t, 1, -1 do
if file:match(pattern) then if not iter(t[i]) then
return true table.remove(t, i)
end end
end end
return false
end end
-- alphanum sorting for humans in Lua -- alphanum sorting for humans in Lua
-- http://notebook.kulchenko.com/algorithms/alphanumeric-natural-sorting-for-humans-in-lua -- http://notebook.kulchenko.com/algorithms/alphanumeric-natural-sorting-for-humans-in-lua
local function alphanumsort(filenames) function alphanumsort(filenames)
local function padnum(n, d) local function padnum(n, d)
return #d > 0 and ("%03d%s%.12f"):format(#n, n, tonumber(d) / (10 ^ #d)) return #d > 0 and ("%03d%s%.12f"):format(#n, n, tonumber(d) / (10 ^ #d))
or ("%03d%s"):format(#n, n) or ("%03d%s"):format(#n, n)
@@ -221,119 +114,38 @@ local function alphanumsort(filenames)
return filenames return filenames
end end
local autoloaded local autoloaded = nil
local added_entries = {}
local autoloaded_dir
local function scan_dir(path, current_file, dir_mode, separator, dir_depth, total_files, extensions) function get_playlist_filenames()
if dir_depth == MAX_DIR_STACK then local filenames = {}
return for n = 0, pl_count - 1, 1 do
end local filename = mp.get_property('playlist/'..n..'/filename')
msg.trace("scanning: " .. path) local _, file = utils.split_path(filename)
local files = utils.readdir(path, "files") or {} filenames[file] = true
local dirs = dir_mode ~= "ignore" and utils.readdir(path, "dirs") or {}
local prefix = path == "." and "" or path
local function filter(t, iter)
for i = #t, 1, -1 do
if not iter(t[i]) then
table.remove(t, i)
end
end
end
filter(files, function(v)
-- Always accept current file
local current = prefix .. v == current_file
if current then
return true
end
if o.ignore_hidden and v:match("^%.") then
return false
end
if is_ignored(v) then
return false
end
local ext = get_extension(v)
return ext and extensions[ext:lower()]
end)
filter(dirs, function(d)
return not (o.ignore_hidden and d:match("^%."))
end)
alphanumsort(files)
alphanumsort(dirs)
for i, file in ipairs(files) do
files[i] = prefix .. file
end
local function append(t1, t2)
local t1_size = #t1
for i = 1, #t2 do
t1[t1_size + i] = t2[i]
end
end
append(total_files, files)
if dir_mode == "recursive" then
for _, dir in ipairs(dirs) do
scan_dir(prefix .. dir .. separator, current_file, dir_mode,
separator, dir_depth + 1, total_files, extensions)
end
else
for i, dir in ipairs(dirs) do
dirs[i] = prefix .. dir
end
append(total_files, dirs)
end end
return filenames
end end
local function find_and_add_entries() function find_and_add_entries()
local aborted = mp.get_property_native("playback-abort")
if aborted then
msg.debug("stopping: playback aborted")
return
end
local path = mp.get_property("path", "") local path = mp.get_property("path", "")
local dir, filename = utils.split_path(path) local dir, filename = utils.split_path(path)
msg.trace(("dir: %s, filename: %s"):format(dir, filename)) msg.trace(("dir: %s, filename: %s"):format(dir, filename))
if o.disabled then if o.disabled then
msg.debug("stopping: autoload disabled") msg.verbose("stopping: autoload disabled")
return return
elseif #dir == 0 then elseif #dir == 0 then
msg.debug("stopping: not a local path") msg.verbose("stopping: not a local path")
return return
end end
local pl_count = mp.get_property_number("playlist-count", 1) pl_count = mp.get_property_number("playlist-count", 1)
local this_ext = get_extension(filename)
-- check if this is a manually made playlist -- check if this is a manually made playlist
if pl_count > 1 and autoloaded == nil then if (pl_count > 1 and autoloaded == nil) or
msg.debug("stopping: manually made playlist") (pl_count == 1 and EXTENSIONS[string.lower(get_extension(filename))] == nil) then
msg.verbose("stopping: manually made playlist")
return return
elseif pl_count == 1 then
autoloaded = true
autoloaded_dir = dir
added_entries = {}
end
local extensions
if o.same_type then
if EXTENSIONS_VIDEO[this_ext:lower()] then
extensions = EXTENSIONS_VIDEO
elseif EXTENSIONS_AUDIO[this_ext:lower()] then
extensions = EXTENSIONS_AUDIO
elseif EXTENSIONS_IMAGES[this_ext:lower()] then
extensions = EXTENSIONS_IMAGES
end
else else
extensions = EXTENSIONS autoloaded = true
end
if not extensions then
msg.debug("stopping: no matched extentions list")
return
end end
local pl = mp.get_property_native("playlist", {}) local pl = mp.get_property_native("playlist", {})
@@ -341,75 +153,69 @@ local function find_and_add_entries()
msg.trace(("playlist-pos-1: %s, playlist: %s"):format(pl_current, msg.trace(("playlist-pos-1: %s, playlist: %s"):format(pl_current,
utils.to_string(pl))) utils.to_string(pl)))
local files = {} local files = utils.readdir(dir, "files")
scan_dir(autoloaded_dir, path, if files == nil then
o.directory_mode or mp.get_property("directory-mode", "lazy"), msg.verbose("no other files in directory")
mp.get_property_native("platform") == "windows" and "\\" or "/",
0, files, extensions)
if next(files) == nil then
msg.debug("no other files or directories in directory")
return return
end end
table.filter(files, function (v, k)
-- The current file could be a hidden file, ignoring it doesn't load other
-- files from the current directory.
if (o.ignore_hidden and not (v == filename) and string.match(v, "^%.")) then
return false
end
local ext = get_extension(v)
if ext == nil then
return false
end
return EXTENSIONS[string.lower(ext)]
end)
alphanumsort(files)
if dir == "." then
dir = ""
end
-- Find the current pl entry (dir+"/"+filename) in the sorted dir list -- Find the current pl entry (dir+"/"+filename) in the sorted dir list
local current local current
for i = 1, #files do for i = 1, #files do
if files[i] == path then if files[i] == filename then
current = i current = i
break break
end end
end end
if not current then if current == nil then
msg.debug("current file not found in directory")
return return
end end
msg.trace("current file position in files: "..current) msg.trace("current file position in files: "..current)
-- treat already existing playlist entries, independent of how they got added
-- as if they got added by autoload
for _, entry in ipairs(pl) do
added_entries[entry.filename] = true
end
local append = {[-1] = {}, [1] = {}} local append = {[-1] = {}, [1] = {}}
local filenames = get_playlist_filenames()
for direction = -1, 1, 2 do -- 2 iterations, with direction = -1 and +1 for direction = -1, 1, 2 do -- 2 iterations, with direction = -1 and +1
for i = 1, MAX_ENTRIES do for i = 1, MAXENTRIES do
local pos = current + i * direction local file = files[current + i * direction]
local file = files[pos]
if file == nil or file[1] == "." then if file == nil or file[1] == "." then
break break
end end
-- skip files that are/were already in the playlist local filepath = dir .. file
if not added_entries[file] then -- skip files already in playlist
if direction == -1 then if filenames[file] then break end
msg.verbose("Prepending " .. file)
table.insert(append[-1], 1, {file, pl_current + i * direction + 1}) if direction == -1 then
else if pl_current == 1 then -- never add additional entries in the middle
msg.verbose("Adding " .. file) msg.info("Prepending " .. file)
if pl_count > 1 then table.insert(append[-1], 1, filepath)
table.insert(append[1], {file, pl_current + i * direction - 1})
else
mp.commandv("loadfile", file, "append")
end
end end
added_entries[file] = true else
msg.info("Adding " .. file)
table.insert(append[1], filepath)
end end
end end
if pl_count == 1 and direction == -1 and #append[-1] > 0 then
local load = append[-1]
for i = 1, #load do
mp.commandv("loadfile", load[i][1], "append")
end
mp.commandv("playlist-move", 0, current)
end
end end
if pl_count > 1 then add_files_at(pl_current + 1, append[1])
add_files(append[1]) add_files_at(pl_current, append[-1])
add_files(append[-1])
end
end end
mp.register_event("start-file", find_and_add_entries) mp.register_event("start-file", find_and_add_entries)

View File

@@ -1,711 +0,0 @@
-- // Bookmarker Menu v1.3.1 for mpv \\ --
-- See README.md for instructions
-- Maximum number of characters for bookmark name
local maxChar = 100
-- Number of bookmarks to be displayed per page
local bookmarksPerPage = 10
-- Whether to close the Bookmarker menu after loading a bookmark
local closeAfterLoad = true
-- Whether to close the Bookmarker menu after replacing a bookmark
local closeAfterReplace = true
-- Whether to ask for confirmation to replace a bookmark (Uses the Typer for confirmation)
local confirmReplace = false
-- Whether to ask for confirmation to delete a bookmark (Uses the Typer for confirmation)
local confirmDelete = false
-- The rate (in seconds) at which the bookmarker needs to refresh its interface; lower is more frequent
local rate = 1.5
-- The filename for the bookmarks file
local bookmarkerName = "bookmarker.json"
-- All the "global" variables and utilities; don't touch these
local utils = require 'mp.utils'
local styleOn = mp.get_property("osd-ass-cc/0")
local styleOff = mp.get_property("osd-ass-cc/1")
local bookmarks = {}
local currentSlot = 0
local currentPage = 1
local maxPage = 1
local active = false
local mode = "none"
local bookmarkStore = {}
local oldSlot = 0
-- // Controls \\ --
-- List of custom controls and their function
local bookmarkerControls = {
ESC = function() abort("") end,
e = function() abort("") end,
DOWN = function() jumpSlot(1) end,
UP = function() jumpSlot(-1) end,
j = function() jumpSlot(1) end,
k = function() jumpSlot(-1) end,
RIGHT = function() jumpPage(1) end,
LEFT = function() jumpPage(-1) end,
O = function() addBookmark() end,
-- O = function() mode="save" typerStart() end,
p = function() mode="replace" typerStart() end,
r = function() mode="rename" typerStart() end,
f = function() mode="filepath" typerStart() end,
m = function() mode="move" moverStart() end,
d = function() mode="delete" typerStart() end,
DEL = function() mode="delete" typerStart() end,
ENTER = function() jumpToBookmark(currentSlot) end,
KP_ENTER = function() jumpToBookmark(currentSlot) end
}
local bookmarkerFlags = {
DOWN = {repeatable = true},
UP = {repeatable = true},
RIGHT = {repeatable = true},
LEFT = {repeatable = true}
}
-- Activate the custom controls
function activateControls(name, controls, flags)
for key, func in pairs(controls) do
mp.add_forced_key_binding(key, name..key, func, flags[key])
end
end
-- Deactivate the custom controls
function deactivateControls(name, controls)
for key, _ in pairs(controls) do
mp.remove_key_binding(name..key)
end
end
-- // Typer \\ --
-- Controls for the Typer
local typerControls = {
ESC = function() typerExit() end,
ENTER = function() typerCommit() end,
KP_ENTER = function() typerCommit() end,
RIGHT = function() typerCursor(1) end,
LEFT = function() typerCursor(-1) end,
BS = function() typer("backspace") end,
DEL = function() typer("delete") end,
SPACE = function() typer(" ") end,
SHARP = function() typer("#") end,
KP0 = function() typer("0") end,
KP1 = function() typer("1") end,
KP2 = function() typer("2") end,
KP3 = function() typer("3") end,
KP4 = function() typer("4") end,
KP5 = function() typer("5") end,
KP6 = function() typer("6") end,
KP7 = function() typer("7") end,
KP8 = function() typer("8") end,
KP9 = function() typer("9") end,
KP_DEC = function() typer(".") end
}
-- All standard keys for the Typer
local typerKeys = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","1","2","3","4","5","6","7","8","9","0","!","@","$","%","^","&","*","(",")","-","_","=","+","[","]","{","}","\\","|",";",":","'","\"",",",".","<",">","/","?","`","~"}
-- For some reason, semicolon is not possible, but it's listed there just in case anyway
local typerText = ""
local typerPos = 0
local typerActive = false
-- Function to activate the Typer
-- use typerStart() for custom controls around activating the Typer
function activateTyper()
for key, func in pairs(typerControls) do
mp.add_forced_key_binding(key, "typer"..key, func, {repeatable=true})
end
for i, key in ipairs(typerKeys) do
mp.add_forced_key_binding(key, "typer"..key, function() typer(key) end, {repeatable=true})
end
typerText = ""
typerActive = true
end
-- Function to deactivate the Typer
-- use typerExit() for custom controls around deactivating the Typer
function deactivateTyper()
for key, _ in pairs(typerControls) do
mp.remove_key_binding("typer"..key)
end
for i, key in ipairs(typerKeys) do
mp.remove_key_binding("typer"..key)
end
typerActive = false
return typerText
end
-- Function to move the cursor of the typer; can wrap around
function typerCursor(direction)
typerPos = typerPos + direction
if typerPos < 0 then typerPos = typerText:len() end
if typerPos > typerText:len() then typerPos = 0 end
typer("")
end
-- Function for handling the text as it is being typed
function typer(s)
-- Don't touch this part
if s == "backspace" then
if typerPos > 0 then
typerText = typerText:sub(1, typerPos - 1) .. typerText:sub(typerPos + 1)
typerPos = typerPos - 1
end
elseif s == "delete" then
if typerPos < typerText:len() then
typerText = typerText:sub(1, typerPos) .. typerText:sub(typerPos + 2)
end
else
if mode == "filepath" or typerText:len() < maxChar then
typerText = typerText:sub(1, typerPos) .. s .. typerText:sub(typerPos + 1)
typerPos = typerPos + s:len()
end
end
-- Enter custom script and display message here
local preMessage = "Enter a bookmark name:"
if mode == "save" then
preMessage = styleOn.."{\\b1}Save a new bookmark with custom name:{\\b0}"..styleOff
elseif mode == "replace" then
preMessage = styleOn.."{\\b1}Type \"y\" to replace the following bookmark:{\\b0}\n"..displayName(bookmarks[currentSlot]["name"])..styleOff
elseif mode == "delete" then
preMessage = styleOn.."{\\b1}Type \"y\" to delete the following bookmark:{\\b0}\n"..displayName(bookmarks[currentSlot]["name"])..styleOff
elseif mode == "rename" then
preMessage = styleOn.."{\\b1}Rename an existing bookmark:{\\b0}"..styleOff
elseif mode == "filepath" then
preMessage = styleOn.."{\\b1}Change the bookmark's filepath:{\\b0}"..styleOff
end
local postMessage = ""
local split = typerPos + math.floor(typerPos / maxChar)
local messageLines = math.floor((typerText:len() - 1) / maxChar) + 1
for i = 1, messageLines do
postMessage = postMessage .. typerText:sub((i-1) * maxChar + 1, i * maxChar) .. "\n"
end
postMessage = postMessage:sub(1,postMessage:len()-1)
mp.osd_message(preMessage.."\n"..postMessage:sub(1,split)..styleOn.."{\\c&H00FFFF&}{\\b1}|{\\r}"..styleOff..postMessage:sub(split+1), 9999)
end
-- // Mover \\ --
-- Controls for the Mover
local moverControls = {
ESC = function() moverExit() end,
DOWN = function() jumpSlot(1) end,
UP = function() jumpSlot(-1) end,
RIGHT = function() jumpPage(1) end,
LEFT = function() jumpPage(-1) end,
s = function() addBookmark() end,
m = function() moverCommit() end,
ENTER = function() moverCommit() end,
KP_ENTER = function() moverCommit() end
}
local moverFlags = {
DOWN = {repeatable = true},
UP = {repeatable = true},
RIGHT = {repeatable = true},
LEFT = {repeatable = true}
}
-- Function to activate the Mover
function moverStart()
if bookmarkExists(currentSlot) then
deactivateControls("bookmarker", bookmarkerControls)
activateControls("mover", moverControls, moverFlags)
displayBookmarks()
else
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the bookmark at slot "..currentSlot)
end
end
-- Function to commit the action of the Mover
function moverCommit()
saveBookmarks()
moverExit()
end
-- Function to deactivate the Mover
-- If isError is set, then it'll abort
function moverExit(isError)
deactivateControls("mover", moverControls)
mode = "none"
if not isError then
loadBookmarks()
displayBookmarks()
activateControls("bookmarker", bookmarkerControls, bookmarkerFlags)
end
end
-- // General utilities \\ --
-- Check if the operating system is Mac OS
function isMacOS()
local homedir = os.getenv("HOME")
return (homedir ~= nil and string.sub(homedir,1,6) == "/Users")
end
-- Check if the operating system is Windows
function isWindows()
local windir = os.getenv("windir")
return (windir~=nil)
end
-- Check whether a certain file exists
function fileExists(path)
local f = io.open(path,"r")
if f~=nil then
io.close(f)
return true
else
return false
end
end
-- Get the filepath of a file from the mpv config folder
function getFilepath(filename)
if isWindows() then
return os.getenv("APPDATA"):gsub("\\", "/") .. "/mpv/" .. filename
else
return os.getenv("HOME") .. "/.config/mpv/" .. filename
end
end
-- Load a table from a JSON file
-- Returns nil if the file can't be found
function loadTable(path)
local contents = ""
local myTable = {}
local file = io.open( path, "r" )
if file then
local contents = file:read( "*a" )
myTable = utils.parse_json(contents);
io.close(file)
return myTable
end
return nil
end
-- Save a table as a JSON file file
-- Returns true if successful
function saveTable(t, path)
local contents = utils.format_json(t)
local file = io.open(path .. ".tmp", "wb")
file:write(contents)
io.close(file)
os.remove(path)
os.rename(path .. ".tmp", path)
return true
end
-- Convert a pos (seconds) to a hh:mm:ss.mmm format
function parseTime(pos)
local hours = math.floor(pos/3600)
local minutes = math.floor((pos % 3600)/60)
local seconds = math.floor((pos % 60))
local milliseconds = math.floor(pos % 1 * 1000)
return string.format("%02d:%02d:%02d.%03d",hours,minutes,seconds,milliseconds)
end
-- // Bookmark functions \\ --
-- Checks whether the specified bookmark exists
function bookmarkExists(slot)
return (slot >= 1 and slot <= #bookmarks)
end
-- Calculates the current page and the total number of pages
function calcPages()
currentPage = math.floor((currentSlot - 1) / bookmarksPerPage) + 1
if currentPage == 0 then currentPage = 1 end
maxPage = math.floor((#bookmarks - 1) / bookmarksPerPage) + 1
if maxPage == 0 then maxPage = 1 end
end
-- Get the amount of bookmarks on the specified page
function getAmountBookmarksOnPage(page)
local n = bookmarksPerPage
if page == maxPage then n = #bookmarks % bookmarksPerPage end
if n == 0 then n = bookmarksPerPage end
if #bookmarks == 0 then n = 0 end
return n
end
-- Get the index of the first slot on the specified page
function getFirstSlotOnPage(page)
return (page - 1) * bookmarksPerPage + 1
end
-- Get the index of the last slot on the specified page
function getLastSlotOnPage(page)
local endSlot = getFirstSlotOnPage(page) + getAmountBookmarksOnPage(page) - 1
if endSlot > #bookmarks then endSlot = #bookmarks end
return endSlot
end
-- Jumps a certain amount of slots forward or backwards in the bookmarks list
-- Keeps in mind if the current mode is to move bookmarks
function jumpSlot(i)
if mode == "move" then
oldSlot = currentSlot
bookmarkStore = bookmarks[oldSlot]
end
currentSlot = currentSlot + i
local startSlot = getFirstSlotOnPage(currentPage)
local endSlot = getLastSlotOnPage(currentPage)
if currentSlot < startSlot then currentSlot = endSlot end
if currentSlot > endSlot then currentSlot = startSlot end
if mode == "move" then
table.remove(bookmarks, oldSlot)
table.insert(bookmarks, currentSlot, bookmarkStore)
end
displayBookmarks()
end
-- Jumps a certain amount of pages forward or backwards in the bookmarks list
-- Keeps in mind if the current mode is to move bookmarks
function jumpPage(i)
if mode == "move" then
oldSlot = currentSlot
bookmarkStore = bookmarks[oldSlot]
end
local oldPos = currentSlot - getFirstSlotOnPage(currentPage) + 1
currentPage = currentPage + i
if currentPage < 1 then currentPage = maxPage + currentPage end
if currentPage > maxPage then currentPage = currentPage - maxPage end
local bookmarksOnPage = getAmountBookmarksOnPage(currentPage)
if oldPos > bookmarksOnPage then oldPos = bookmarksOnPage end
currentSlot = getFirstSlotOnPage(currentPage) + oldPos - 1
if mode == "move" then
table.remove(bookmarks, oldSlot)
table.insert(bookmarks, currentSlot, bookmarkStore)
end
displayBookmarks()
end
-- Parses a bookmark name for storing, also trimming it
-- Replaces %t with the timestamp of the bookmark
-- Replaces %p with the time position of the bookmark
function parseName(name)
local pos = 0
if mode == "rename" then pos = bookmarks[currentSlot]["pos"] else pos = mp.get_property_number("time-pos") end
name, _ = name:gsub("%%t", parseTime(pos))
name, _ = name:gsub("%%p", pos)
name = trimName(name)
return name
end
-- Parses a bookmark name for displaying, also trimming it
-- Replaces all { with an escaped { so it won't be interpreted as a tag
function displayName(name)
name, _ = name:gsub("{", "\\{")
name = trimName(name)
return name
end
-- Trims a name to the max number of characters
function trimName(name)
if name:len() > maxChar then name = name:sub(1,maxChar) end
return name
end
-- Parses a Windows path with backslashes to one with normal slashes
function parsePath(path)
if type(path) == "string" then path, _ = path:gsub("\\", "/") end
return path
end
-- Loads all the bookmarks in the global table and sets the current page and total number of pages
-- Also checks for older versions of bookmarks and "updates" them
-- Also checks for bookmarks made by "mpv-bookmarker" and converts them
-- Also removes anything it doesn't recognize as a bookmark
function loadBookmarks()
bookmarks = loadTable(getFilepath(bookmarkerName))
if bookmarks == nil then bookmarks = {} end
local doSave = false
local doEject = false
local doReplace = false
local ejects = {}
local newmarks = {}
for key, bookmark in pairs(bookmarks) do
if type(key) == "number" then
if bookmark.version == nil or bookmark.version == 1 then
if bookmark.name ~= nil and bookmark.path ~= nil and bookmark.pos ~= nil then
bookmark.path = parsePath(bookmark.path)
bookmark.version = 2
doSave = true
else
table.insert(ejects, key)
doEject = true
end
end
else
if bookmark.filename ~= nil and bookmark.pos ~= nil and bookmark.filepath ~= nil then
local newmark = {
name = trimName(""..bookmark.filename.." @ "..parseTime(bookmark.pos)),
pos = bookmark.pos,
path = parsePath(bookmark.filepath),
version = 2
}
table.insert(newmarks, newmark)
end
doReplace = true
doSave = true
end
end
if doEject then
for i = #ejects, 1, -1 do table.remove(bookmarks, ejects[i]) end
doSave = true
end
if doReplace then bookmarks = newmarks end
if doSave then saveBookmarks() end
if #bookmarks > 0 and currentSlot == 0 then currentSlot = 1 end
calcPages()
end
-- Save the globally loaded bookmarks to the JSON file
function saveBookmarks()
saveTable(bookmarks, getFilepath(bookmarkerName))
end
-- Make a bookmark of the current media file, position and name
-- Name can be specified or left blank to automake a name
-- Returns the bookmark if successful or nil if it can't make a bookmark
function makeBookmark(bname)
if mp.get_property("path") ~= nil then
if bname == nil then bname = mp.get_property("media-title").." @ %t" end
local bookmark = {
name = parseName(bname),
pos = mp.get_property_number("time-pos"),
path = parsePath(mp.get_property("path")),
version = 2
}
return bookmark
else
return nil
end
end
-- Add the current position as a bookmark to the global table and then saves it
-- Returns the slot of the newly added bookmark
-- Returns -1 if there's an error
function addBookmark(name)
local bookmark = makeBookmark(name)
if bookmark == nil then
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the media file to create the bookmark for")
return -1
end
table.insert(bookmarks, bookmark)
if #bookmarks == 1 then currentSlot = 1 end
calcPages()
saveBookmarks()
displayBookmarks()
return #bookmarks
end
-- Edit a property of a bookmark at the specified slot
-- Returns -1 if there's an error
function editBookmark(slot, property, value)
if bookmarkExists(slot) then
if property == "name" then value = parseName(value) end
bookmarks[slot][property] = value
saveBookmarks()
else
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the bookmark at slot "..slot)
return -1
end
end
-- Replaces the bookmark at the specified slot with a provided bookmark
-- Keeps the name and its position in the list
-- If the slot is not specified, picks the currently selected bookmark to replace
-- If a bookmark is not provided, generates a new bookmark
function replaceBookmark(slot)
if slot == nil then slot = currentSlot end
if bookmarkExists(slot) then
local bookmark = makeBookmark(bookmarks[slot]["name"])
if bookmark == nil then
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the media file to create the bookmark for")
return -1
end
bookmarks[slot] = bookmark
saveBookmarks()
if closeAfterReplace then
abort(styleOn.."{\\c&H00FF00&}{\\b1}Successfully replaced bookmark:{\\r}\n"..displayName(bookmark["name"]))
return -1
end
return 1
else
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the bookmark at slot "..slot)
return -1
end
end
-- Quickly saves a bookmark without bringing up the menu
function quickSave()
if not active then
loadBookmarks()
local slot = addBookmark()
if slot > 0 then mp.osd_message("Saved new bookmark at slot " .. slot) end
end
end
-- Quickly loads the last bookmark without bringing up the menu
function quickLoad()
if not active then
loadBookmarks()
local slot = #bookmarks
if slot > 0 then mp.osd_message("Loaded bookmark at slot " .. slot) end
jumpToBookmark(slot)
end
end
-- Deletes the bookmark in the specified slot from the global table and then saves it
function deleteBookmark(slot)
table.remove(bookmarks, slot)
if currentSlot > #bookmarks then currentSlot = #bookmarks end
calcPages()
saveBookmarks()
displayBookmarks()
end
-- Jump to the specified bookmark
-- This means loading it, reading it, and jumping to the file + position in the bookmark
function jumpToBookmark(slot)
if bookmarkExists(slot) then
local bookmark = bookmarks[slot]
if string.sub(bookmark["path"], 1, 4) == "http" or fileExists(bookmark["path"]) then
if parsePath(mp.get_property("path")) == bookmark["path"] then
mp.set_property_number("time-pos", bookmark["pos"])
else
mp.commandv("loadfile", parsePath(bookmark["path"]), "replace", -1, "start="..bookmark["pos"]) end
if closeAfterLoad then abort(styleOn.."{\\c&H00FF00&}{\\b1}Successfully found file for bookmark:{\\r}\n"..displayName(bookmark["name"])) end
else
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find file for bookmark:\n" .. displayName(bookmark["name"]))
end
else
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the bookmark at slot " .. slot)
end
end
-- Displays the current page of bookmarks
function displayBookmarks()
-- Determine which slot is the first and last on the current page
local startSlot = getFirstSlotOnPage(currentPage)
local endSlot = getLastSlotOnPage(currentPage)
-- Prepare the text to display and display it
local display = styleOn .. "{\\b1}Bookmarks page " .. currentPage .. "/" .. maxPage .. ":{\\b0}"
for i = startSlot, endSlot do
local btext = displayName(bookmarks[i]["name"])
local selection = ""
if i == currentSlot then
selection = "{\\b1}{\\c&H00FFFF&}>"
if mode == "move" then btext = "----------------" end
btext = btext
end
display = display .. "\n" .. selection .. i .. ": " .. btext .. "{\\r}"
end
mp.osd_message(display, rate)
end
local timer = mp.add_periodic_timer(rate * 0.95, displayBookmarks)
timer:kill()
-- Commits the message entered with the Typer with custom scripts preceding it
-- Should typically end with typerExit()
function typerCommit()
local status = 0
if mode == "save" then
status = addBookmark(typerText)
elseif mode == "replace" and typerText == "y" then
status = replaceBookmark(currentSlot, makeBookmark(bookmarks[currentSlot]["name"]))
elseif mode == "delete" and typerText == "y" then
deleteBookmark(currentSlot)
elseif mode == "rename" then
editBookmark(currentSlot, "name", typerText)
elseif mode == "filepath" then
editBookmark(currentSlot, "path", typerText)
end
if status >= 0 then typerExit() end
end
-- Exits the Typer without committing with custom scripts preceding it
function typerExit()
deactivateTyper()
displayBookmarks()
timer:resume()
mode = "none"
activateControls("bookmarker", bookmarkerControls, bookmarkerFlags)
end
-- Starts the Typer with custom scripts preceding it
function typerStart()
if (mode == "save" or mode=="replace") and mp.get_property("path") == nil then
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the media file to create the bookmark for")
return -1
end
if (mode == "replace" or mode == "rename" or mode == "filepath" or mode == "delete") and not bookmarkExists(currentSlot) then
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the bookmark at slot "..currentSlot)
return -1
end
if (mode == "replace" and not confirmReplace) or (mode == "delete" and not confirmDelete) then
typerText = "y"
typerCommit()
return
end
deactivateControls("bookmarker", bookmarkerControls)
timer:kill()
activateTyper()
if mode == "rename" then typerText = bookmarks[currentSlot]["name"] end
if mode == "filepath" then typerText = bookmarks[currentSlot]["path"] end
typerPos = typerText:len()
typer("")
end
-- Aborts the program with an optional error message
function abort(message)
mode = "none"
moverExit(true)
deactivateTyper()
deactivateControls("bookmarker", bookmarkerControls)
timer:kill()
mp.osd_message(message)
active = false
end
-- Handles the state of the bookmarker
function handler()
if active then
abort("")
else
activateControls("bookmarker", bookmarkerControls, bookmarkerFlags)
loadBookmarks()
displayBookmarks()
timer:resume()
active = true
end
end
mp.register_script_message("bookmarker-menu", handler)
mp.register_script_message("bookmarker-quick-save", quickSave)
mp.register_script_message("bookmarker-quick-load", quickLoad)

33
mpv/scripts/copy-time.lua Normal file
View File

@@ -0,0 +1,33 @@
-- copy-time (Linux version)
-- Requires xclip installed
-- Copies current timecode in HH:MM:SS.MS format to clipboard
-------------------------------------------------------------------------------
-- Script adapted by Alex Rogers (https://github.com/linguisticmind)
-- Modified from https://github.com/Arieleg/mpv-copyTime
-- Released under GNU GPL 3.0
require "mp"
local function set_clipboard(text)
command = string.format("echo -n %s | xclip -selection clipboard", text)
mp.commandv("run", "/bin/bash", "-c", command)
end
function copy_time()
local time_pos = mp.get_property_number("time-pos")
local time_in_seconds = time_pos
local time_seg = time_pos % 60
time_pos = time_pos - time_seg
local time_hours = math.floor(time_pos / 3600)
time_pos = time_pos - (time_hours * 3600)
local time_minutes = time_pos/60
time_seg,time_ms=string.format("%.03f", time_seg):match"([^.]*).(.*)"
time = string.format("%02d:%02d:%02d.%s", time_hours, time_minutes, time_seg, time_ms)
set_clipboard(time)
mp.osd_message(string.format("Copied to clipboard: %s", time))
end
-- the keybinding here is set to nil on purpose 'cause I modified the keybinding (in input.conf)
mp.add_key_binding(nil, "copy-time", copy_time)

View File

@@ -0,0 +1,58 @@
--[=====[
script to cycle commands with a keybind, accomplished through script messages
available at: https://github.com/CogentRedTester/mpv-scripts
syntax:
script-message cycle-commands "command1" "command2" "command3"
The syntax of each command is identical to the standard input.conf syntax, but each command must be within
a pair of double quotes.
Commands with mutiword arguments require you to send double quotes just like normal command syntax, however,
you will need to escape the quotes with a backslash so that they are sent as part of the string.
Semicolons also work exactly like they do normally, so you can easily send multiple commands each cycle.
Here is an example of a standard input.conf entry:
script-message cycle-commands "show-text one 1000 ; print-text two" "show-text \"three four\""
This would, on keypress one, print 'one' to the OSD for 1 second and 'two' to the console,
and on keypress two 'three four' would be printed to the OSD.
Notice how the quotation marks around 'three four' are escaped using backslashes.
All other syntax details should be exactly the same as usual input commands.
There are no limits to the number of commands, and the script message can be used as often as one wants,
the script stores the current iteration for each unique cycle command, so there should be no overlap
unless one binds the exact same command string (including spacing)
]=====]--
local mp = require 'mp'
local msg = require 'mp.msg'
--keeps track of the current position for a specific cycle
local iterators = {}
--main function to identify and run the cycles
local function main(...)
local commands = {...}
--to identify the specific cycle we'll concatenate all the strings together to use as our table key
local str = table.concat(commands, " | ")
msg.trace('recieved:', str)
if iterators[str] == nil then
msg.debug('unknown cycle, creating iterator')
iterators[str] = 1
else
iterators[str] = iterators[str] + 1
if iterators[str] > #commands then iterators[str] = 1 end
end
--mp.command should run the commands exactly as if they were entered in input.conf.
--This should provide universal support for all input.conf command syntax
local cmd = commands[ iterators[str] ]
msg.verbose('sending command:', cmd)
mp.command(cmd)
end
mp.register_script_message('cycle-commands', main)

View File

@@ -0,0 +1,105 @@
--[[
script to cycle profiles with a keybind, accomplished through script messages
available at: https://github.com/CogentRedTester/mpv-scripts
syntax:
script-message cycle-profiles "profile1;profile2;profile3"
You must use semicolons to separate the profiles, do not include any spaces that are not part of the profile name.
The script will print the profile description to the screen when switching, if there is no profile description, then it just prints the name
]]--
--change this to change what character separates the profile names
seperator = ";"
msg = require 'mp.msg'
--splits the profiles string into an array of profile names
--function taken from: https://stackoverflow.com/questions/1426954/split-string-in-lua/7615129#7615129
function mysplit (inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={}
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
table.insert(t, str)
end
return t
end
--table of all available profiles and options
profileList = mp.get_property_native('profile-list')
--keeps track of current profile for every unique cycle
iterator = {}
--stores descriptions for profiles
--once requested a description is stored here so it does not need to be found again
profilesDescs = {}
--if trying to cycle to an unknown profile this function is run to find a description to print
function findDesc(profile)
msg.verbose('unknown profile ' .. profile .. ', searching for description')
for i = 1, #profileList, 1 do
if profileList[i]['name'] == profile then
msg.verbose('profile found')
local desc = profileList[i]['profile-desc']
if desc ~= nil then
msg.verbose('description found')
profilesDescs[profile] = desc
else
msg.verbose('no description, will use name')
profilesDescs[profile] = profile
end
return
end
end
msg.verbose('profile not found')
profilesDescs[profile] = "no profile '" .. profile .. "'"
end
--prints the profile description to the OSD
--if the profile has not been requested before during the session then it runs findDesc()
function printProfileDesc(profile)
local desc = profilesDescs[profile]
if desc == nil then
findDesc(profile)
desc = profilesDescs[profile]
end
msg.verbose('profile description: ' .. desc)
mp.osd_message(desc)
end
function main(profileStr)
--if there is not already an iterator for this cycle then it creates one
if iterator[profileStr] == nil then
msg.verbose('unknown cycle, creating new iterator')
iterator[profileStr] = 1
end
local i = iterator[profileStr]
--converts the string into an array of profile names
local profiles = mysplit(profileStr, seperator)
msg.verbose('cycling ' .. tostring(profiles))
msg.verbose("number of profiles: " .. tostring(#profiles))
--sends the command to apply the profile
msg.info("applying profile " .. profiles[i])
mp.commandv('apply-profile', profiles[i])
--prints the profile description to the OSD
printProfileDesc(profiles[i])
--moves the iterator
iterator[profileStr] = iterator[profileStr] + 1
if iterator[profileStr] > #profiles then
msg.verbose('reached end of profiles, wrapping back to start')
iterator[profileStr] = 1
end
end
mp.register_script_message('cycle-profiles', main)

View File

@@ -1,227 +0,0 @@
# mpv-file-browser
![cover](screenshots/bunny.png)
This script allows users to browse and open files and folders entirely from within mpv. The script uses nothing outside the mpv API, so should work identically on all platforms. The browser can move up and down directories, start playing files and folders, or add them to the queue.
By default only file types compatible with mpv will be shown, but this can be changed in the config file.
This script requires at least **mpv v0.33**.
Originally, file-browser worked with versions of mpv going back to
v0.31, you can find those older versions of file-browser in the
[mpv-v0.31 branch](https://github.com/CogentRedTester/mpv-file-browser/tree/mpv-v0.31).
That branch will no longer be receiving any feature updates,
but I will try to fix any bugs that are reported on the issue
tracker.
## Installation
### Basic
Clone this git repository into the mpv `~~/scripts` directory and
change the name of the folder from `mpv-file-browser` to `file-browser`.
You can then pull to receive updates.
Alternatively, you can download the zip and extract the contents to `~~/scripts/file-browser`.
`~~/` is the mpv config directory which is typically `~/.config/mpv/` on linux and `%APPDATA%/mpv/` on windows.
Create a `file_browser.conf` file in the `~~/script-opts/` directory and customise the [`root` option](#root-directory) for your
system. The [`docs/file_browser.conf`](docs/file_browser.conf) file contains the full list of options and their defaults.
<details>
<summary>Expected directory tree:</summary>
```
~~/
├── script-opts
│   └── file-browser.conf
└── scripts
   └── file-browser
      ├── addons/
      ├── docs/
      ├── modules/
      ├── screenshots/
      ├── LICENSE
      ├── main.lua
      └── README.md
```
</details>
### Advanced
To setup [custom keybinds](docs/custom-keybinds.md) enable the `custom_keybinds` option in `file_browser.conf` and
create a `~~/script-opts/file-browser-keybinds.json` file. Do **not** copy the `file-browser-keybinds.json` file
stored in this repository, that file is a collection of random examples, many of which are for completely different
operating systems. Use them and the [docs](docs/custom-keybinds.md) to create your own collection of keybinds.
To setup [addons](addons/README.md) enable the `addons` option in `file_browser.conf` and place the addon files
in the `~~/script-modules/file-browser-addons/` directory.
If you are not going to enable custom keybinds or addons then there is no reason to
create `file-browser-keybinds.json` or `script-modules/file-browser-addons/`.
<details>
<summary>Expected directory tree:</summary>
```
~~/
├── script-modules
│   └── file-browser-addons
│   ├── addon1.lua
│   ├── addon2.lua
│   └── etc.lua
├── script-opts
│   ├── file_browser.conf
│   └── file-browser-keybinds.json
└── scripts
   └── file-browser
      ├── addons/
      ├── docs/
      ├── modules/
      ├── screenshots/
      ├── LICENSE
      ├── main.lua
      └── README.md
```
</details>
## Keybinds
The following keybinds are set by default
| Key | Name | Description |
|-------------|----------------------------------|-------------------------------------------------------------------------------|
| MENU | browse-files | toggles the browser |
| Ctrl+o | open-browser | opens the browser |
| Alt+o | browse-directory/get-user-input | opens a dialogue box to type in a directory - requires [mpv-user-input](#mpv-user-input) when mpv < v0.38 |
The following dynamic keybinds are only set while the browser is open:
| Key | Name | Description |
|-------------|---------------|-------------------------------------------------------------------------------|
| ESC | close | closes the browser or clears the selection |
| ENTER | play | plays the currently selected file or folder |
| Shift+ENTER | play_append | appends the current file or folder to the playlist |
| Alt+ENTER | play_autoload | loads playlist entries before and after the selected file (like autoload.lua) |
| RIGHT | down_dir | enter the currently selected directory |
| LEFT | up_dir | move to the parent directory |
| DOWN | scroll_down | move selector down the list |
| UP | scroll_up | move selector up the list |
| PGDWN | page_down | move selector down the list by a page (the num_entries option) |
| PGUP | page_up | move selector up the list by a page (the num_entries option) |
| Shift+PGDWN | list_bottom | move selector to the bottom of the list |
| Shift+PGUP | list_top | move selector to the top of the list |
| HOME | goto_current | move to the directory of the currently playing file |
| Shift+HOME | goto_root | move to the root directory |
| Ctrl+r | reload | reload directory and reset cache |
| s | select_mode | toggles multiselect mode |
| S | select_item | toggles selection for the current item |
| Ctrl+a | select_all | select all items in the current directory |
When attempting to play or append a subtitle file the script will instead load the subtitle track into the existing video.
The behaviour of the autoload keybind can be reversed with the `autoload` script-opt.
By default the playlist will only be autoloaded if `Alt+ENTER` is used on a single file, however when the option is switched autoload will always be used on single files *unless* `Alt+ENTER` is used. Using autoload on a directory, or while appending an item, will not work.
## Root Directory
To accomodate for both windows and linux this script has its own virtual root directory where drives and file folders can be manually added. The root directory can only contain folders.
The root directory is set using the `root` option, which is a comma separated list of directories. Entries are sent through mpv's `expand-path` command. By default the only root value is the user's home folder:
`root=~/`
It is highly recommended that this be customised for the computer being used; [file_browser.conf](file_browser.conf) contains commented out suggestions for generic linux and windows systems. For example, my windows root looks like:
`root=~/,C:/,D:/,E:/,Z:/`
## Multi-Select
By default file-browser only opens/appends the single item that the cursor has selected.
However, using the `s` keybinds specified above, it is possible to select multiple items to open all at once. Selected items are shown in a different colour to the cursor.
When in multiselect mode the cursor changes colour and scrolling up and down the list will drag the current selection. If the original item was unselected, then dragging will select items, if the original item was selected, then dragging will unselect items.
When multiple items are selected using the open or append commands all selected files will be added to the playlist in the order they appear on the screen.
The currently selected (with the cursor) file will be ignored, instead the first multi-selected item in the folder will follow replace/append behaviour as normal, and following selected items will be appended to the playlist afterwards in the order that they appear on the screen.
## Custom Keybinds
File-browser also supports custom keybinds. These keybinds send normal input commands, but the script will substitute characters in the command strings for specific values depending on the currently open directory, and currently selected item.
This allows for a wide range of customised behaviour, such as loading additional audio tracks from the browser, or copying the path of the selected item to the clipboard.
To see how to enable and use custom keybinds, see [custom-keybinds.md](docs/custom-keybinds.md).
## Add-ons
Add-ons are ways to add extra features to file-browser, for example adding support for network file servers like ftp, or implementing virtual directories in the root like recently opened files.
They can be enabled by setting `addon` script-opt to yes, and placing the addon file into the `~~/script-modules/file-browser-addons/` directory.
For a list of existing addons see the [wiki](https://github.com/CogentRedTester/mpv-file-browser/wiki/Addon-List).
For instructions on writing your own addons see [addons.md](docs/addons.md).
## Script Messages
File-browser supports a small number of script messages that allow the user or other scripts to talk with the browser.
### `browse-directory`
`script-message browse-directory [directory]`
Opens the given directory in the browser. If the browser is currently closed it will be opened.
### `get-directory-contents`
`script-message get-directory-contents [directory] [response-string]`
Reads the given directory, and sends the resulting tables to the specified script-message in the format:
`script-message [response-string] [list] [opts]`
The [list](docs/addons.md#the-list-array)
and [opts](docs/addons.md#the-opts-table)
tables are formatted as json strings through the `mp.utils.format_json` function.
See [addons.md](docs/addons.md) for how the tables are structured, and what each field means.
The API_VERSION field of the `opts` table refers to what version of the addon API file browser is using.
The `response-string` refers to an arbitrary script-message that the tables should be sent to.
This script-message allows other scripts to utilise file-browser's directory parsing capabilities, as well as those of the file-browser addons.
## Configuration
See [file_browser.conf](docs/file_browser.conf) for the full list of options and their default values.
The file is placed in the `~~/script-opts/` folder.
## Conditional Auto-Profiles
file-browser provides a property that can be used with [conditional auto-profiles](https://mpv.io/manual/master/#conditional-auto-profiles)
to detect when the browser is open.
On mpv v0.36+ you should use the `user-data` property with the `file_browser/open` boolean.
Here is an example of an auto-profile that hides the OSC logo when using file-browser in an idle window:
```properties
[hide-logo]
profile-cond= idle_active and user_data.file_browser.open
profile-restore=copy
osc=no
```
On older versions of mpv you can use the `file_browser-open` field of the `shared-script-properties` property:
```properties
[hide-logo]
profile-cond= idle_active and shared_script_properties["file_browser-open"] == "yes"
profile-restore=copy
osc=no
```
See [#55](https://github.com/CogentRedTester/mpv-file-browser/issues/55) for more details on this.
## [mpv-user-input](https://github.com/CogentRedTester/mpv-user-input)
mpv-user-input is a script that provides an API to request text input from the user over the OSD.
It was built using `console.lua` as a base, so supports almost all the same text input commands.
If `user-input.lua` is loaded by mpv, and `user-input-module` is in the `~~/script-modules/` directory,
then using `Alt+o` will open an input box that can be used to directly enter directories for file-browser to open.
Mpv v0.38 added the `mp.input` module, which means `mpv-user-input` is no-longer necessary from that version onwards.

View File

@@ -1,12 +0,0 @@
# addons
Add-ons are ways to add extra features to file-browser, for example adding support for network file servers like ftp, or implementing virtual directories in the root like recently opened files.
They can be enabled by setting `addon` script-opt to yes, and placing the addon file into the `~~/script-modules/file-browser-addons/` directory.
Browsing filesystems provided by add-ons should feel identical to the normal handling of the script,
but they may require extra commandline tools be installed.
Since addons are loaded programatically from the addon directory it is possible for anyone to write their own addon.
Instructions on how to do this are available [here](../docs/addons.md).
For a list of available addons see the [wiki](https://github.com/CogentRedTester/mpv-file-browser/wiki/Addon-List).

View File

@@ -1,89 +0,0 @@
--[[
An addon for mpv-file-browser which adds support for apache http directory indexes
]]--
local mp = require 'mp'
local msg = require 'mp.msg'
local utils = require 'mp.utils'
local fb = require "file-browser"
--decodes a URL address
--this piece of code was taken from: https://stackoverflow.com/questions/20405985/lua-decodeuri-luvit/20406960#20406960
local decodeURI
do
local char, gsub, tonumber = string.char, string.gsub, tonumber
local function _(hex) return char(tonumber(hex, 16)) end
function decodeURI(s)
s = gsub(s, '%%(%x%x)', _)
return s
end
end
local apache = {
priority = 80,
api_version = "1.1.0"
}
function apache:can_parse(name)
return name:find("^https?://")
end
--send curl errors through the browser empty_text
function apache:send_error(str)
return {}, {empty_text = "curl error: "..str}
end
local function execute(args)
msg.trace(utils.to_string(args))
local _, cmd = fb.get_parse_state():yield(
mp.command_native_async({
name = "subprocess",
playback_only = false,
capture_stdout = true,
capture_stderr = true,
args = args
}, fb.coroutine.callback())
)
return cmd
end
function apache:parse(directory)
msg.verbose(directory)
local test = execute({"curl", "-k", "-l", "-I", directory})
local response = test.stdout:match("(%d%d%d [^\n\r]+)")
if test.stdout:match("Content%-Type: ([^\r\n/]+)") ~= "text" then return nil end
if response ~= "200 OK" then return self:send_error(response) end
local html = execute({"curl", "-k", "-l", directory})
if html.status ~= 0 then return self:send_error(tostring(html.status))
elseif not html.stdout:find("%[PARENTDIR%]") then return nil end
html = html.stdout
local list = {}
for str in string.gmatch(html, "[^\r\n]+") do
local valid = true
if str:sub(1,4) ~= "<tr>" then valid = false end
local link = str:match('href="(.-)"')
local alt = str:match('alt="%[(.-)%]"')
if valid and not alt or not link then valid = false end
if valid and alt == "PARENTDIR" or alt == "ICO" then valid = false end
if valid and link:find("[:?<>|]") then valid = false end
local is_dir = (alt == "DIR")
if valid and is_dir and not self.valid_dir(link) then valid = false end
if valid and not is_dir and not self.valid_file(link) then valid = false end
if valid then
msg.trace(alt..": "..link)
table.insert(list, { name = link, type = (is_dir and "dir" or "file"), label = decodeURI(link) })
end
end
return list, {filtered = true, directory_label = decodeURI(directory)}
end
return apache

View File

@@ -1,191 +0,0 @@
--[[
An addon for mpv-file-browser which adds a Favourites path that can be loaded from the ROOT
]]--
local mp = require "mp"
local msg = require "mp.msg"
local utils = require "mp.utils"
local save_path = mp.command_native({"expand-path", "~~/script-opts/file_browser_favourites.txt"})
do
local file = io.open(save_path, "a+")
if not file then
msg.error("cannot access file", ("%q"):format(save_path), "make sure that the directory exists")
return {}
end
file:close()
end
local favourites = nil
local favs = {
api_version = "1.4.0",
priority = 30,
cursor = 1
}
local use_virtual_directory = true
local full_paths = {}
local function create_favourite_object(str)
local item = {
type = str:sub(-1) == "/" and "dir" or "file",
path = str,
redirect = not use_virtual_directory,
name = str:match("([^/]+/?)$")
}
full_paths[str:match("([^/]+)/?$")] = str
return item
end
function favs:setup()
self:register_root_item('Favourites/')
end
local function update_favourites()
favourites = {}
local file = io.open(save_path, "r")
if not file then return end
for str in file:lines() do
table.insert(favourites, create_favourite_object(str))
end
file:close()
end
function favs:can_parse(directory)
return directory:find("Favourites/") == 1
end
function favs:parse(directory)
if not favourites then update_favourites() end
if directory == "Favourites/" then
local opts = {
filtered = true,
sorted = true
}
if self.cursor ~= 1 then opts.selected_index = self.cursor ; self.cursor = 1 end
return favourites, opts
end
if use_virtual_directory then
-- converts the relative favourite path into a full path
local name = directory:match("Favourites/([^/]+)/?")
local _, finish = directory:find("Favourites/([^/]+/?)")
local full_path = (full_paths[name] or "")..directory:sub(finish+1)
local list, opts = self:defer(full_path or "")
if not list then return nil end
opts.id = self:get_id()
if opts.directory_label then
opts.directory_label = opts.directory_label:gsub(full_paths[name], "Favourites/"..name..'/')
if opts.directory_label:find("Favourites/") ~= 1 then opts.directory_label = nil end
end
for _, item in ipairs(list) do
if not item.path then item.redirect = false end
item.path = item.path or full_path..item.name
end
return list, opts
end
local path = full_paths[ directory:match("([^/]+/?)$") or "" ]
local list, opts = self:defer(path)
if not list then return nil end
opts.directory = opts.directory or path
return list, opts
end
local function get_favourite(path)
for index, value in ipairs(favourites) do
if value.path == path then return index, value end
end
end
--update the browser with new contents of the file
local function update_browser()
if favs.get_directory():find("[fF]avourites/") then
if favs.get_directory():find("[fF]avourites/$") then
local cursor = favs.get_selected_index()
favs.rescan()
favs.set_selected_index(cursor)
favs.redraw()
else
favs.clear_cache()
end
end
end
--write the contents of favourites to the file
local function write_to_file()
local file = io.open(save_path, "w+")
if not file then return msg.error(file, "could not open favourites file") end
for _, item in ipairs(favourites) do
file:write(string.format("%s\n", item.path))
end
file:close()
end
local function add_favourite(path)
if get_favourite(path) then return end
update_favourites()
table.insert(favourites, create_favourite_object(path))
write_to_file()
end
local function remove_favourite(path)
update_favourites()
local index = get_favourite(path)
if not index then return end
table.remove(favourites, index)
write_to_file()
end
local function move_favourite(path, direction)
update_favourites()
local index, item = get_favourite(path)
if not index or not favourites[index + direction] then return end
favourites[index] = favourites[index + direction]
favourites[index + direction] = item
write_to_file()
end
local function toggle_favourite(cmd, state, co)
local path = favs.get_full_path(state.list[state.selected], state.directory)
if state.directory:find("[fF]avourites/$") then remove_favourite(path)
else add_favourite(path) end
update_browser()
end
local function move_key(cmd, state, co)
if not state.directory:find("[fF]avourites/") then return false end
local path = favs.get_full_path(state.list[state.selected], state.directory)
local cursor = favs.get_selected_index()
if cmd.name == favs:get_id().."/move_up" then
move_favourite(path, -1)
favs.set_selected_index(cursor-1)
else
move_favourite(path, 1)
favs.set_selected_index(cursor+1)
end
update_browser()
end
update_favourites()
mp.register_script_message("favourites/add_favourite", add_favourite)
mp.register_script_message("favourites/remove_favourite", remove_favourite)
mp.register_script_message("favourites/move_up", function(path) move_favourite(path, -1) end)
mp.register_script_message("favourites/move_down", function(path) move_favourite(path, 1) end)
favs.keybinds = {
{ "F", "toggle_favourite", toggle_favourite, {}, },
{ "Ctrl+UP", "move_up", move_key, {repeatable = true} },
{ "Ctrl+DOWN", "move_down", move_key, {repeatable = true} },
}
return favs

View File

@@ -1,104 +0,0 @@
--[[
An addon for mpv-file-browser for searching the current directory
Available at: https://github.com/CogentRedTester/mpv-file-browser/tree/master/addons
Requires mpv-user-input: https://github.com/CogentRedTester/mpv-user-input
Keybinds:
Ctrl+f open search box
Ctrl+F open advanced search box (supports Lua patterns)
n cycle to next valid item
]]--
local msg = require "mp.msg"
local fb = require "file-browser"
local input_loaded, input = pcall(require, "mp.input")
local user_input_loaded, user_input = pcall(require, "user-input-module")
local find = {
api_version = "1.3.0"
}
local latest_coroutine = nil
local global_fb_state = getmetatable(fb.get_state()).__original
local function compare(name, query)
if name:find(query) then return true end
if name:lower():find(query) then return true end
if name:upper():find(query) then return true end
return false
end
local function main(key, state, co)
if not state.list then return false end
local text
if key.name == "find/find" then text = "Find: enter search string"
else text = "Find: enter advanced search string" end
if input_loaded then
input.get({
prompt = text .. "\n>",
id = "file-browser/find",
submit = fb.coroutine.callback(),
})
elseif user_input_loaded then
user_input.get_user_input( fb.coroutine.callback(), { text = text, id = "find", replace = true } )
end
local query, error = coroutine.yield()
if input_loaded then input.terminate() end
if not query then return msg.debug(error) end
-- allow the directory to be changed before this point
local list = fb.get_list()
local parse_id = global_fb_state.co
if key.name == "find/find" then
query = fb.pattern_escape(query)
end
local results = {}
for index, item in ipairs(list) do
if compare(item.label or item.name, query) then
table.insert(results, index)
end
end
if (#results < 1) then
msg.warn("No matching items for '"..query.."'")
return
end
--keep cycling through the search results if any are found
--putting this into a separate coroutine removes any passthrough ambiguity
--the final return statement should return to `step_find` not any other function
fb.coroutine.run(function()
latest_coroutine = coroutine.running()
while (true) do
for _, index in ipairs(results) do
fb.set_selected_index(index)
coroutine.yield(true)
if parse_id ~= global_fb_state.co then
latest_coroutine = nil
return false
end
end
end
end)
end
local function step_find()
if not latest_coroutine then return false end
return fb.coroutine.resume_err(latest_coroutine)
end
find.keybinds = {
{"Ctrl+f", "find", main, {}},
{"Ctrl+F", "find_advanced", main, {}},
{"n", "next", step_find, {}},
}
return find

View File

@@ -1,86 +0,0 @@
--[[
An addon for mpv-file-browser which adds support for ftp servers
]]--
local mp = require 'mp'
local msg = require 'mp.msg'
local utils = require 'mp.utils'
local fb = require 'file-browser'
local ftp = {
priority = 100,
api_version = "1.1.0"
}
function ftp:can_parse(directory)
return directory:sub(1, 6) == "ftp://"
end
--in my experience curl has been somewhat unreliable when it comes to ftp requests
--this fuction retries the request a few times just in case
local function execute(args)
msg.debug(utils.to_string(args))
local _, cmd = fb.get_parse_state():yield(
mp.command_native_async({
name = "subprocess",
playback_only = false,
capture_stdout = true,
capture_stderr = true,
args = args
}, fb.coroutine.callback())
)
return cmd
end
-- encodes special characters using the URL percent encoding format
function urlEncode(url)
local domain, path = string.match(url, '(ftp://[^/]-/)(.*)')
if not path then return url end
-- these are the unreserved URI characters according to RFC 3986
-- https://www.rfc-editor.org/rfc/rfc3986#section-2.3
path = string.gsub(path, '[^%w.~_%-]', function(c)
return ('%%%x'):format(string.byte(c))
end)
return domain..path
end
function ftp:parse(directory)
msg.verbose(directory)
local ftp = execute({"curl", "-k", "-g", "--retry", "4", urlEncode(directory)})
local entries = execute({"curl", "-k", "-g", "-l", "--retry", "4", urlEncode(directory)})
if entries.status == 28 then
msg.error(entries.stderr)
elseif entries.status ~= 0 or ftp.status ~= 0 then
msg.error(entries.stderr)
return
end
local response = {}
for str in string.gmatch(ftp.stdout, "[^\r\n]+") do
table.insert(response, str)
end
local list = {}
local i = 1
for str in string.gmatch(entries.stdout, "[^\r\n]+") do
if str and response[i] then
msg.trace(str .. ' | ' .. response[i])
if response[i]:sub(1,1) == "d" then
table.insert(list, { name = str..'/', type = "dir" })
else
table.insert(list, { name = str, type = "file" })
end
i = i+1
end
end
return list
end
return ftp

View File

@@ -1,27 +0,0 @@
--[[
An addon for mpv-file-browser which displays ~/ for the home directory instead of the full path
]]--
local mp = require "mp"
local fb = require "file-browser"
local home = fb.fix_path(mp.command_native({"expand-path", "~/"}), true)
local home_label = {
priority = 100,
api_version = "1.0.0"
}
function home_label:can_parse(directory)
return directory:sub(1, home:len()) == home
end
function home_label:parse(directory)
local list, opts = self:defer(directory)
if (not opts.directory or opts.directory == directory) and not opts.directory_label then
opts.directory_label = "~/"..(directory:sub(home:len()+1) or "")
end
return list, opts
end
return home_label

View File

@@ -1,56 +0,0 @@
--[[
An addon for mpv-file-browser which stores the last opened directory and
sets it as the opened directory the next time mpv is opened.
Available at: https://github.com/CogentRedTester/mpv-file-browser/tree/master/addons
]]--
local mp = require 'mp'
local msg = require 'mp.msg'
local fb = require 'file-browser'
local state_file = mp.command_native({'expand-path', '~~state/last_opened_directory'})
msg.verbose('using', state_file)
local function write_directory(directory)
local file = io.open(state_file, 'w+')
if not file then return msg.error('could not open', state_file, 'for writing') end
directory = directory or fb.get_directory()
msg.verbose('writing', directory, 'to', state_file)
file:write(directory)
file:close()
end
local addon = {
api_version = '1.7.0',
priority = 0,
}
function addon:setup()
local file = io.open(state_file, "r")
if not file then
return msg.error('failed to open', state_file, 'for reading')
end
local dir = file:read("*a")
msg.verbose('setting default directory to', dir)
fb.browse_directory(dir, false)
file:close()
end
function addon:can_parse(dir, parse_state)
if parse_state.source == 'browser' then write_directory(dir) end
return false
end
function addon:parse()
return nil
end
mp.register_event('shutdown', function() write_directory() end)
return addon

View File

@@ -1,57 +0,0 @@
--[[
An addon for mpv-file-browser which uses the Linux ls command to parse native directories
This behaves near identically to the native parser, but IO is done asynchronously.
Available at: https://github.com/CogentRedTester/mpv-file-browser/tree/master/addons
]]--
local mp = require "mp"
local msg = require "mp.msg"
local fb = require "file-browser"
local ls = {
priority = 109,
api_version = "1.1.0",
name = "ls",
keybind_name = "file"
}
local function command(args, parse_state)
local _, cmd = parse_state:yield(
mp.command_native_async({
name = "subprocess",
playback_only = false,
capture_stdout = true,
capture_stderr = true,
args = args
}, fb.coroutine.callback())
)
return cmd.status == 0 and cmd.stdout or nil
end
function ls:can_parse(directory)
return directory ~= '' and not fb.get_protocol(directory)
end
function ls:parse(directory, parse_state)
local list = {}
local files = command({"ls", "-1", "-p", "-A", "-N", "--zero", directory}, parse_state)
if not files then return nil end
for str in files:gmatch("%Z+") do
local is_dir = str:sub(-1) == "/"
msg.trace(str)
if is_dir and fb.valid_dir(str) then
table.insert(list, {name = str, type = "dir"})
elseif fb.valid_file(str) then
table.insert(list, {name = str, type = "file"})
end
end
return list, {filtered = true}
end
return ls

View File

@@ -1,54 +0,0 @@
--[[
An addon for mpv-file-browser which adds support for m3u playlists
If the first entry of a playlist isn't working it is because some playlists are created with random invisible unicode in the first line
Vim makes it easy to detect these
This addon requires that my API mpv-read-file be available in ~~/script-modules/
https://github.com/CogentRedTester/mpv-read-file
]]--
local rf = require "read-file"
local m3u = {
priority = 100,
api_version = "1.0.0",
name = "m3u"
}
local full_paths = {}
function m3u:setup()
self.register_parseable_extension("m3u")
self.register_parseable_extension("m3u8")
end
function m3u:can_parse(directory)
return directory:find("m3u8?/?$")
end
function m3u:parse(directory)
directory = directory:gsub("/$", "")
local list = {}
local path = full_paths[ directory ] or directory
local playlist = rf.get_file_handler( path )
--if we can't read the path then stop here
if not playlist then return {}, {sorted = true, filtered = true, empty_text = "Could not read filepath"} end
local parent = self.fix_path(path:match("^(.+/[^/]+)/"), true)
local lines = playlist:read("*a")
for item in lines:gmatch("[^%c]+") do
item = self.fix_path(item)
local fullpath = self.join_path(parent, item)
local name = ( self.get_protocol(item) and item or fullpath:match("([^/]+)/?$") )
table.insert(list, {name = name, path = fullpath, type = "file"})
end
return list, {filtered = true, sorted = true}
end
return m3u

View File

@@ -1,81 +0,0 @@
--[[
An addon for mpv-file-browser which uses powershell commands to parse native directories
This is slower than the default parser for local drives, but faster for network drives
The drive_letters array below is used to list the drives to use this parser for
]]--
--list the drive letters to use here (case sensitive)
local drive_letters = {
"Y", "Z"
}
local mp = require "mp"
local msg = require "mp.msg"
local fb = require "file-browser"
local wn = {
priority = 109,
api_version = "1.1.0",
name = "powershell",
keybind_name = "file"
}
local drives = {}
for _, letter in ipairs(drive_letters) do
drives[letter] = true
end
local function command(args, parse_state)
local _, cmd = parse_state:yield(
mp.command_native_async({
name = "subprocess",
playback_only = false,
capture_stdout = true,
capture_stderr = true,
args = args
}, fb.coroutine.callback())
)
return cmd.status == 0 and cmd.stdout or nil, cmd.stderr
end
function wn:can_parse(directory)
return directory ~= '' and not self.get_protocol(directory) and drives[ directory:sub(1,1) ]
end
function wn:parse(directory, parse_state)
local list = {}
local files, err = command({"powershell", "-noprofile", "-command", [[
$dirs = Get-ChildItem -LiteralPath ]]..string.format("%q", directory)..[[ -Directory
$files = Get-ChildItem -LiteralPath ]]..string.format("%q", directory)..[[ -File
foreach ($n in $dirs.Name) {
$n += "/"
$u8clip = [System.Text.Encoding]::UTF8.GetBytes($n)
[Console]::OpenStandardOutput().Write($u8clip, 0, $u8clip.Length)
Write-Host ""
}
foreach ($n in $files.Name) {
$u8clip = [System.Text.Encoding]::UTF8.GetBytes($n)
[Console]::OpenStandardOutput().Write($u8clip, 0, $u8clip.Length)
Write-Host ""
}
]]}, parse_state)
if not files then msg.debug(err) ; return nil end
for str in files:gmatch("[^\n\r]+") do
local is_dir = str:sub(-1) == "/"
if is_dir and self.valid_dir(str) then
table.insert(list, {name = str, type = "dir"})
elseif self.valid_file(str) then
table.insert(list, {name = str, type = "file"})
end
end
return self.sort(list), {filtered = true, sorted = true}
end
return wn

View File

@@ -1,54 +0,0 @@
--[[
An addon that loads root items from a `~~/script-opts/file-browser-root.json` file.
The contents of this file will override the root script-opt.
The json file takes the form of a list array as defined by the addon API:
https://github.com/CogentRedTester/mpv-file-browser/blob/master/addons/addons.md#the-list-array
The main purpose of this addon is to allow for users to customise the appearance of their root items
using the label or ass fields:
[
{ "name": "Favourites/" },
{ "label": "~/", "name": "C:/Users/User/" },
{ "label": "1TB HDD", "name": "D:/" },
{ "ass": "{\\c&H007700&}Green Text", "name": "E:/" },
{ "label": "FTP Server", name: "ftp://user:password@server.com/" }
]
Make sure local directories always end with `/`.
`path` and `name` behave the same in the root but either name or label should have a value.
ASS styling codes: https://aegi.vmoe.info/docs/3.0/ASS_Tags/
]]
local mp = require 'mp'
local msg = require 'mp.msg'
local utils = require 'mp.utils'
local fb = require 'file-browser'
-- loads the root json file
local config_path = mp.command_native({'expand-path', '~~/script-opts/file-browser-root.json'})
local file = io.open(config_path, 'r')
if not file then
msg.error('failed to read file', config_path)
return
end
local root_config = utils.parse_json(file:read("*a"))
if not root_config then
msg.error('failed to parse contents of', config_path, '- Check the syntax is correct.')
return
end
local function setup()
for i, item in ipairs(root_config) do
fb.register_root_item(item, item.priority)
end
end
return {
api_version = '1.4.0',
setup = setup,
priority = -1000,
}

View File

@@ -1,35 +0,0 @@
--[[
An addon for file-browser which decodes URLs so that they are more readable
]]
local urldecode = {
priority = 5,
api_version = "1.0.0"
}
--decodes a URL address
--this piece of code was taken from: https://stackoverflow.com/questions/20405985/lua-decodeuri-luvit/20406960#20406960
local decodeURI
do
local char, gsub, tonumber = string.char, string.gsub, tonumber
local function _(hex) return char(tonumber(hex, 16)) end
function decodeURI(s)
s = gsub(s, '%%(%x%x)', _)
return s
end
end
function urldecode:can_parse(directory)
return self.get_protocol(directory)
end
function urldecode:parse(directory)
local list, opts = self:defer(directory)
if opts.directory and not self.get_protocol(opts.directory) then return list, opts end
opts.directory_label = decodeURI(opts.directory_label or (opts.directory or directory))
return list, opts
end
return urldecode

View File

@@ -1,97 +0,0 @@
--[[
An addon for mpv-file-browser which uses the Windows dir command to parse native directories
This behaves near identically to the native parser, but IO is done asynchronously.
Available at: https://github.com/CogentRedTester/mpv-file-browser/tree/master/addons
]]--
local mp = require "mp"
local msg = require "mp.msg"
local fb = require "file-browser"
--this is a LuaJit module this addon will not load if not using LuaJit
local ffi = require 'ffi'
ffi.cdef([[
int __stdcall WideCharToMultiByte(unsigned int CodePage, unsigned int dwFlags, const wchar_t *lpWideCharStr, int cchWideChar, char *lpMultiByteStr, int cbMultiByte, const char *lpDefaultChar, bool *lpUsedDefaultChar);
]])
--converts a UTF16 string to a UTF8 string
--this function was adapted from https://github.com/mpv-player/mpv/issues/10139#issuecomment-1117954648
local function utf8(WideCharStr)
WideCharStr = ffi.cast("wchar_t*", WideCharStr)
if not WideCharStr then return nil end
local utf8_size = ffi.C.WideCharToMultiByte(65001, 0, WideCharStr, -1, nil, 0, nil, nil) --CP_UTF8
if utf8_size > 0 then
local utf8_path = ffi.new("char[?]", utf8_size)
local utf8_size = ffi.C.WideCharToMultiByte(65001, 0, WideCharStr, -1, utf8_path, utf8_size, nil, nil)
if utf8_size > 0 then
--removes the trailing `\0` character which can break things
return ffi.string(utf8_path, utf8_size):sub(1, -2)
end
end
end
local dir = {
priority = 109,
api_version = "1.1.0",
name = "cmd-dir",
keybind_name = "file"
}
local function command(args, parse_state)
local _, cmd = parse_state:yield(
mp.command_native_async({
name = "subprocess",
playback_only = false,
capture_stdout = true,
capture_stderr = true,
args = args,
}, fb.coroutine.callback() )
)
cmd.stdout = utf8(cmd.stdout)
cmd.stderr = utf8(cmd.stderr)
--dir returns this exact error message if the directory is empty
if cmd.status == 1 and cmd.stderr == "File Not Found\r\n" then cmd.status = 0 end
return cmd.status == 0 and cmd.stdout or nil, cmd.stderr
end
function dir:can_parse(directory)
if directory == "" then return end
return not fb.get_protocol(directory)
end
function dir:parse(directory, parse_state)
local list = {}
local files, dirs, err
-- the dir command expects backslashes for our paths
directory = directory:gsub("/", "\\")
dirs, err = command({ "cmd", "/U", "/c", "dir", "/b", "/ad", directory }, parse_state)
if not dirs then return msg.error(err) end
files, err = command({ "cmd", "/U", "/c", "dir", "/b", "/a-d", directory }, parse_state)
if not files then return msg.error(err) end
for name in dirs:gmatch("[^\n\r]+") do
name = name.."/"
if fb.valid_dir(name) then
table.insert(list, { name = name, type = "dir" })
msg.trace(name)
end
end
for name in files:gmatch("[^\n\r]+") do
if fb.valid_file(name) then
table.insert(list, { name = name, type = "file" })
msg.trace(name)
end
end
return list, { filtered = true }
end
return dir

View File

@@ -1,52 +0,0 @@
--[[
Automatically populates the root with windows drives on startup.
Ctrl+r will add new drives mounted since startup.
Drives will only be added if they are not already present in the root.
Available at: https://github.com/CogentRedTester/mpv-file-browser/tree/master/addons
]]
local mp = require 'mp'
local msg = require 'mp.msg'
local fb = require 'file-browser'
-- returns a list of windows drives
local function get_drives()
local result = mp.command_native({
name = 'subprocess',
playback_only = false,
capture_stdout = true,
args = {'fsutil', 'fsinfo', 'drives'}
})
if result.status ~= 0 then return msg.error('could not read windows root') end
local root = {}
for drive in result.stdout:gmatch("(%a:)\\") do
table.insert(root, drive..'/')
end
return root
end
-- adds windows drives to the root if they are not already present
local function import_drives()
local drives = get_drives()
for _, drive in ipairs(drives) do
fb.register_root_item(drive)
end
end
local keybind = {
key = 'Ctrl+r',
name = 'import_root_drives',
command = import_drives,
parser = 'root',
passthrough = true
}
return {
api_version = '1.4.0',
setup = import_drives,
keybinds = { keybind }
}

View File

@@ -1,958 +0,0 @@
# How to Write an Addon - API v1.7.0
Addons provide ways for file-browser to parse non-native directory structures. This document describes how one can create their own custom addon.
If you have an independent script but want to use file-browser's parsing capabilities, perhaps to make use of existing addons, then look [here](https://github.com/CogentRedTester/mpv-file-browser#get-directory-contents).
## Terminology
For the purpose of this document addons refer to the scripts being loaded while parsers are the objects the scripts return.
An addon can return multiple parsers, but when they only returns one the terms are almost synonymous.
Additionally, `method` refers to functions called using the `object:funct()` syntax, and hence have access to the self object, whereas `function` is the standard `object.funct()` syntax.
## API Version
The API version, shown in the title of this document, allows file-browser to ensure that addons are using the correct
version of the API. It follows [semantic versioning](https://semver.org/) conventions of `MAJOR.MINOR.PATCH`.
A parser sets its version string with the `version` field, as seen [below](#overview).
Any change that breaks backwards compatability will cause the major version number to increase.
A parser MUST have the same major version number as the API, otherwise an error message will be printed and the parser will
not be loaded.
A minor version number denotes a change to the API that is backwards compatible. This includes additional API functions,
or extra fields in tables that were previously unused. It may also include additional arguments to existing functions that
add additional behaviour without changing the old behaviour.
If the parser's minor version number is greater than the API_VERSION, then a warning is printed to the console.
Patch numbers denote bug fixes, and are ignored when loading an addon.
For this reason addon authors are allowed to leave the patch number out of their version tag and just use `MAJOR.MINOR`.
## Overview
File-browser automatically loads any lua files from the `~~/script-modules/file-browser-addons` directory as modules.
Each addon must return either a single parser table, or an array of parser tables. Each parser object must contain the following three members:
| key | type | arguments | returns | description |
|-----------|--------|---------------------------|------------------------|--------------------------------------------------------------------------------------------------------------|
| priority | number | - | - | a number to determine what order parsers are tested - see [here](#priority-suggestions) for suggested values |
| api_version| string | - | - | the API version the parser is using - see [API Version](#api-version) |
| can_parse | method | string, parse_state_table | boolean | returns whether or not the given path is compatible with the parser |
| parse | method | string, parse_state_table | list_table, opts_table | returns an array of item_tables, and a table of options to control how file_browser handles the list |
Additionally, each parser can optionally contain:
| key | type | arguments | returns | description |
|--------------|--------|-----------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| name | string | - | - | the name of the parser used for debug messages and to create a unique id - by default uses the filename with `.lua` or `-browser.lua` removed |
| keybind_name | string | - | - | the name to use when setting custom keybind filters - uses the value of name by default but can be set manually so that the same keys work with multiple addons |
| setup | method | - | - | if it exists this method is automatically run after all parsers are imported and API functions are made available |
| keybinds | table | - | - | an array of keybind objects for the browser to set when loading - see [#keybinds] |
All parsers are given a unique string ID based on their name. If there are collisions then numbers are appended to the end of the name until a free name is found.
These IDs are primarily used for debug messages, though they may gain additional functionality in the future.
Here is an extremely simple example of an addon creating a parser table and returning it to file-browser.
```lua
local parser = {
api_version = '1.0.0',
priority = 100,
name = "example" -- this parser will have the id 'example' or 'example_#' if there are duplicates
}
function parser:can_parse(directory)
return directory == "Example/"
end
function parser:parse(directory, state)
local list, opts
------------------------------
--- populate the list here ---
------------------------------
return list, opts
end
return parser
```
## Parsing
When a directory is loaded file-browser will iterate through the list of parsers from lowest to highest priority.
The first parser for which `can_parse` returns true will be selected as the parser for that directory.
The `parse` method will then be called on the selected parser, which is expected to return either a table of list items, or nil.
If an empty table is returned then file-browser will treat the directory as empty, otherwise if the list_table is nil then file-browser will attempt to run `parse` on the next parser for which `can_parse` returns true.
This continues until a parser returns a list_table, or until there are no more parsers.
The entire parse operation is run inside of a coroutine, this allows parsers to pause execution to handle asynchronous operations.
Please read [coroutines](#coroutines) for all the details.
### Parse State Table
The `parse` and `can_parse` functions are passed a state table as its second argument, this contains the following fields.
| key | type | description |
|----------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| source | string | the source of the parse request |
| directory | string | the directory of the parse request - for debugging purposes |
| already_deferred | boolean | whether or not [defer](#advanced-functions) was called during this parse, if so then file-browser will not try to query any more parsers after receiving the result - set automatically, but can be manually disabled |
| yield | method | a wrapper around `coroutine.yield()` - see [coroutines](#coroutines) |
| is_coroutine_current | method | returns if the browser is waiting on the current coroutine to populate the list |
`already_deferred` is an optimisation. If a script uses defer and still returns nil, then that means that none of the remaining parsers will be able to parse the path.
Therefore, it is more efficient to just immediately jump to the root.
It is up to the addon author to manually disable this if their use of `defer` conflicts with this assumption.
Source can have the following values:
| source | description |
|----------------|---------------------------------------------------------------------------------------------------------|
| browser | triggered by the main browser window |
| loadlist | the browser is scanning the directory to append to the playlist |
| script-message | triggered by the `get-directory-contents` script-message |
| addon | caused by an addon calling the `parse_directory` API function - note that addons can set a custom state |
Note that all calls to any `parse` function during a specific parse request will be given the same parse_state table.
This theoretically allows parsers to communicate with parsers of a lower priority (or modify how they see source information),
but no guarantees are made that specific keys will remain unused by the API.
#### Coroutines
Any calls to `parse()` (or `can_parse()`, but you should never be yielding inside there) are done in a [Lua coroutine](https://www.lua.org/manual/5.1/manual.html#2.11).
This means that you can arbitrarily pause the parse operation if you need to wait for some asynchronous operation to complete,
such as waiting for user input, or for a network request to complete.
Making these operations asynchronous has performance
advantages as well, for example recursively opening a network directory tree could cause the browser to freeze
for a long period of time. If the network query were asynchronous then the browser would only freeze during actual operations,
during network operations it would be free for the user interract with. The browser has even been designed so that
a loadfile/loadlist operation saves it's own copy of the current directory, so even if the user hops around like crazy the original
open operation will still occur in the correct order (though there's nothing stopping them starting a new operation which will cause
random ordering.)
However, there is one downside to this behaviour. If the parse operation is requested by the browser, then it is
possible for the user to change directories while the coroutine is yielded. If you were to resume the coroutine
in that situation, then any operations you do are wasted, and unexpected bahaviour could happen.
file-browser will automatically detect when it receives a list from an aborted coroutine, so there is no risk
of the current list being replaced, but any other logic in your script will continue until `parse` returns.
To fix this there are two methods available in the state table, the `yield()` method is a wrapper around `coroutine.yield()` that
detects when the browser has abandoned the parse, and automatically kills the coroutine by throwing an error.
The `is_coroutine_current()` method simply compares if the current coroutine (as returned by `coroutine.running()`) matches the
coroutine that the browser is waiting for. Remember this is only a problem when the browser is the source of the request,
if the request came from a script-message, or from a loadlist command there are no issues.
### The List Array
The list array must be made up of item_tables, which contain details about each item in the directory.
Each item has the following members:
| key | type | required | description |
|-------------|-----------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------|
| name | string | yes | name of the item, and the string to append after the directory when opening a file/folder |
| type | string | yes | determines whether the item is a file ("file") or directory ("dir") |
| label | string | no | an alternative string to print to the screen instead of name |
| ass | string | no | a string to print to the screen without escaping ass styling - overrides label and name |
| path | string | no | opening the item uses this full path instead of appending directory and name |
| redirect | bool | no | whether `path` should redirect the browser when opening a directory - default yes (nil counts as true) |
| mpv_options | string or table | no | a list of options to be sent to mpv when loading the file - can be in the form `opt1=value1,opt2=value2,...` or a table of string keys and values |
File-browser expects that `type` and `name` will be set for each item, so leaving these out will probably crash the script.
File-browser also assumes that all directories end in a `/` when appending name, and that there will be no backslashes.
The API function [`fix_path`](#utility-functions) can be used to ensure that paths conform to file-browser rules.
Here is an example of a static list table being returned by the `parse` method.
This would allow one to specify a custom list of items.
```lua
function parser:parse(directory, state)
local list = {
{ name = "first/", type = "dir" },
{ name = "second/", type = "dir" },
{ name = "third/", type = "dir" },
{ name = "file%01", type = "file", label = "file1" },
{ name = "file2", type = "file", path = "https://youtube.com/video" },
}
return list
end
```
### The Opts Table
The options table allows scripts to better control how they are handled by file-browser.
None of these values are required, and the opts table can even left as nil when returning.
| key | type | description |
|-----------------|---------|------------------------------------------------------------------------------------------------------------------------------|
| filtered | boolean | if true file-browser will not run the standard filter() function on the list |
| sorted | boolean | if true file-browser will not sort the list |
| directory | string | changes the browser directory to this - used for redirecting to other locations |
| directory_label | string | display this label in the header instead of the actual directory - useful to display encoded paths |
| empty_text | string | display this text when the list is empty - can be used for error messages |
| selected_index | number | the index of the item on the list to select by default - a.k.a. the cursor position |
| id | number | id of the parser that successfully returns a list - set automatically, but can be set manually to take ownership (see defer) |
The previous static example, but modified so that file browser does not try to filter or re-order the list:
```lua
function parser:parse(directory, state)
local list = {
{ name = "first/", type = "dir" },
{ name = "second/", type = "dir" },
{ name = "third/", type = "dir" },
{ name = "file%01", type = "file", label = "file1" },
{ name = "file2", type = "file", path = "https://youtube.com/video" },
}
return list, { sorted = true, filtered = true }
end
```
`id` is used to declare ownership of a page. The name of the parser that has ownership is used for custom-keybinds parser filtering.
When using `defer` id will be the id of whichever parser first returned a list.
This is the only situation when a parser may want to set id manually.
## Priority Suggestions
Below is a table of suggested priority ranges:
| Range | Suggested Use | Example parsers |
|---------|------------------------------------------------------------------------------------------------|------------------------------------------------|
| 0-20 | parsers that purely modify the results of other parsers | [m3u-fixer](m3u-browser.lua) |
| 21-40 | virtual filesystems which need to link to the results of other parsers | [favourites](favourites.lua) |
| 41-50 | to support specific sites or systems which can be inferred from the path | |
| 51-80 | limitted support for specific protocols which requires complex parsing to verify compatability | [apache](apache-browser.lua) |
| 81-90 | parsers that only need to modify the results of full parsers | [home-label](home-label.lua) |
| 91-100 | use for parsers which fully support a non-native protocol with absolutely no overlap | [ftp](ftp-browser.lua), [m3u](m3u-browser.lua) |
| 101-109 | replacements for the native file parser or fallbacks for the full parsers | [powershell](powershell.lua) |
| 110 | priority of the native file parser - don't use | |
| 111+ | fallbacks for native parser - potentially alternatives to the default root | |
## Keybinds
Addons have the ability to set custom keybinds using the `keybinds` field in the `parser` table. `keybinds` must be an array of tables, each of which may be in two forms.
Firstly, the keybind_table may be in the form
`{ "key", "name", [function], [flags] }`
where the table is an array whose four values corresond to the four arguments for the [mp.add_key_binding](https://mpv.io/manual/master/#lua-scripting-[,flags]]\)) API function.
```lua
local function main(keybind, state, co)
-- deletes files
end
parser.keybinds = {
{ "Alt+DEL", "delete_files", main, {} },
}
```
Secondly, the keybind_table may use the same formatting as file-browser's [custom-keybinds](../custom-keybinds.md).
Using the array form is equivalent to setting `key`, `name`, `command`, and `flags` of the custom-keybind form, and leaving everything else on the defaults.
```lua
parser.keybinds = {
{
key = "Alt+DEL",
name = "delete_files",
command = {"run", "rm", "%F"},
filter = "files"
}
}
```
These keybinds are evaluated only once shortly after the addon is loaded, they cannot be modified dynamically during runtime.
Keybinds are applied after the default keybinds, but before the custom keybinds. This means that addons can overwrite the
default keybinds, but that users can ovewrite addon keybinds. Among addons, those with higher priority numbers have their keybinds loaded before those
with lower priority numbers.
Remember that a lower priority value is better, they will overwrite already loaded keybinds.
Keybind passthrough works the same way, though there is some custom behaviour when it comes to [raw functions](#keybind-functions).
### Keybind Names
In either form the naming of the function is different from custom keybinds. Instead of using the form `file_browser/dynamic/custom/[name]`
they use the form `file_browser/dynamic/[parser_ID]/[name]`, where `[parser_id]` is a unique string ID for the parser, which can be retrieved using the
`parser:get_id()` method.
### Native Functions vs Command Tables
There are two ways of specifying the behaviour of a keybind.
It can be in command table form, as done when using custom-keybind syntax, and it can be done in
native function form, as done when using the `mp.add_key_binding` syntax.
However, these two ways of specifying commands are independant of how the overall keybind is defined.
What this means is that the command field of the custom-keybinds syntax can be an array, and the
3rd value in the array syntax can be a table of mpv commands.
```lua
local function main(keybind, state, co)
-- deletes files
end
-- this is a valid keybind table
parser.keybinds = {
{ "Alt+DEL", "delete_files", {"run", "rm", "%F"}, {} },
{
key = "Alt+DEL",
name = "delete_files",
command = main
}
}
```
There are some limitations however, not all custom-keybind options are supported when using native functions.
The supported options are: `key`, `name`, `condition`, `flags`, `parser`, `passthrough`. The other options can be replicated manually (see below).
### Keybind Functions
This section details the use of keybind functions.
#### Function Call
If one uses the raw function then the functions are called directly in the form:
`fn(keybind, state, coroutine)`
Where `keybind` is the keybind_table of the key being run, `state` is a table of state values at the time of the key press, and `coroutine` is the coroutine object
that the keybind is being executed inside.
The `keybind` table uses the same fields as defined
in [custom-keybinds.md](../custom-keybinds.md). Any random extra fields placed in the original
`file-browser-keybinds.json` will likely show up as well (this is not guaranteed).
Note that even if the array form is used, the `keybind` table will still use the custom-keybind format.
The entire process of running a keybind is handled with a coroutine, so the addon can safely pause and resume the coroutine at will. The `state` table is provided to
allow addons to keep a record of important state values that may be changed during a paused coroutine.
#### State Table
The state table contains copies of the following values at the time of the key press.
| key | description |
|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
| directory | the current directory |
| directory_label | the current directory_label - can (and often will) be `nil` |
| list | the current list_table |
| selected | index of the currently selected list item |
| selection | table of currently selected items (for multi-select) - in the form { index = true, ... } - always available even if the `multiselect` flag is not set |
| parser | a copy of the parser object that provided the current directory |
The following example shows the implementation of the `delete_files` keybind using the state values:
```lua
local fb = require "file-browser" -- see #api-functions and #utility-functions
local function main(keybind, state, co)
for index, item in state.list do
if state.selection[index] and item.type == "file" then
os.remove( fb.get_full_path(item, state.directory) )
end
end
end
parser.keybinds = {
{ "Alt+DEL", "delete_files", main, {} },
}
```
#### Passthrough
If the `passthrough` field of the keybind_table is set to `true` or `false` then file-browser will
handle everything. However, if the passthrough field is not set (meaning the bahviour should be automatic)
then it is up to the addon to ensure that they are
correctly notifying when the operation failed and a passthrough should occur.
In order to tell the keybind handler to run the next priority command, the keybind function simply needs to return the value `false`,
any other value (including `nil`) will be treated as a successful operation.
The below example only allows removing files from the `/tmp/` directory and allows other
keybinds to run in different directories:
```lua
local fb = require "file-browser" -- see #api-functions and #utility-functions
local function main(keybind, state, co)
if state.directory ~= "/tmp/" then return false end
for index, item in state.list do
if state.selection[index] and item.type == "file" then
os.remove( fb.get_full_path(item, state.directory) )
end
end
end
parser.keybinds = {
{ "Alt+DEL", "delete_files", main, {} },
}
```
## The API
The API is available through a module, which can be loaded with `require "file-browser"`.
The API provides a variety of different values and functions for an addon to use
in order to make them more powerful.
Function definitions are written using Typescript-style type annotations.
```lua
local fb = require "file-browser"
local parser = {
priority = 100,
}
function parser:setup()
fb.register_root_item("Example/")
end
return parser
```
### Parser API
In addition to the standard API there is also an extra parser API that provides
several parser specific methods, listed below using `parser:method` instead of `fb.function`.
This API is added to the parser object after it is loaded by file-browser,
so if a script wants to call them immediately on load they must do so in the `setup` method.
All the standard API functions are also available in the parser API.
```lua
local parser = {
priority = 100,
}
function parser:setup()
-- same operations
self.insert_root_item({ name = "Example/", type = "dir" })
parser.insert_root_item({ name = "Example/", type = "dir" })
end
-- will not work since the API hasn't been added to the parser yet
parser.insert_root_item({ name = "Example/", type = "dir" })
return parser
```
### General Functions
#### `fb.API_VERSION: string`
The current API version in use by file-browser.
#### `fb.add_default_extension(ext: string): void`
Adds the given extension to the default extension filter whitelist. Can only be run inside the `setup()` method.
#### `fb.browse_directory(directory: string, open_browser: bool = true): coroutine`
Clears the cache and opens the given directory in the browser.
If the `open_browser` argument is truthy or `nil` then the browser will be opened
if it is currently closed. If `open_browser` is `false` then the directory will
be opened in the background.
Returns the coroutine of the upcoming parse operation. The parse is queued and run when the script thread next goes idle,
allowing one to store this value and use it to identify the triggered parse operation.
This is the equivalent of calling the `browse-directory` script-message.
#### `fb.insert_root_item(item: item_table, pos?: number): void`
Add an item_table to the root list at the specified position. If `pos` is nil then append to the end of the root.
`item` must be a valid item_table of `type='dir'`.
#### `fb.register_directory_mapping(directory: string | nil, mapping: string, pattern?: bool): void`
Creates a directory mapping for the given directory. A directory mapping is a
one-way mapping from an external directory string, to an internal directory
within file-browser's directory tree. It allows external paths that may not
exist within file-browser's tree to be mapped to a location that is.
Internally, this is used by file-browser to map the `bd://`, `dvd://`, and `cdda://`
protocol paths to their respective device locations in the filesystem.
Note that as this is still an experimental feature, the exact situations when mappings
are resolved is subject to change. Currently, mapping occurs only when
receiving a directory from an external source, such as the mpv `path` property,
or the `browse-directory` script message.
`directory` is a string that represents a location within file-browser's file-system.
`mapping` is a string that will be replaced by the `directory` string if found in a path:
```lua
fb.register_directory_mapping('/dev/dvd', 'dvd://')
fb.resolve_directory_mapping('dvd://1') -- /dev/dvd/1
```
There can only be one `directory` string associated with each unique `mapping` string,
but multiple mappings can point to the same directory.
If `directory` is set to `nil` then the existing mapping for `mapping` will be removed.
If `pattern` is set to true, then `mapping` will be treated as a Lua
pattern. Any part of an input path that matches the pattern will be substituted for
the `directory` string.
```lua
fb.register_directory_mapping('/dev/dvd', '^dvd://.*', true)
fb.resolve_directory_mapping('dvd://1') -- /dev/dvd
```
When `pattern` is falsy, `mapping` is equivalent to `'^'..fb.pattern_escape(mapping)`.
Captures in the pattern may be given extra behaviour in the future.
#### `fb.register_parseable_extension(ext: string): void`
Register a file extension that the browser will attempt to open, like a directory - for addons which can parse files such
as playlist files.
#### `fb.register_root_item(item: string | item_table, priority?: number): boolean`
Registers an item to be added to the root and an optional priority value that determines the position relative to other items (default is 100).
A lower priority number is better, meaning they will be placed earlier in the list.
Only adds the item if it is not already in the root and returns a boolean that specifies whether or not the item was added.
Must be called during or after the `parser:setup()` method is run.
If `item` is a string then a new item_table is created with the values: `{ type = 'dir', name = item }`.
If `item` is an item_table then it must be a valid directory item.
Use [`fb.fix_path(name, true)`](#fbfix_pathpath-string-is_directory-boolean-string) to ensure the name field is correct.
This function should be used over the older `fb.insert_root_item`.
#### `fb.remove_parseable_extension(ext: string): void`
Remove a file extension that the browser will attempt to open like a directory.
#### `fb.parse_directory(directory: string, parse?: parse_state_table): (list_table, opts_table) | nil`
Starts a new scan for the given directory and returns a list_table and opts_table on success and `nil` on failure.
Must be called from inside a [coroutine](#coroutines).
This function allows addons to request the contents of directories from the loaded parsers. There are no protections
against infinite recursion, so be careful about calling this from within another parse.
Do not use the same `parse` table for multiple parses, state values for the two operations may intefere with each other
and cause undefined behaviour. If the `parse.source` field is not set then it will be set to `"addon"`.
Note that this function is for creating new parse operations, if you wish to create virtual directories or modify
the results of other parsers then use [`defer`](#parserdeferdirectory-string-list_table-opts_table--nil).
Also note that every parse operation is expected to have its own unique coroutine. This acts as a unique
ID that can be used internally or by other addons. This means that if multiple `parse_directory` operations
are run within a single coroutine then file-browser will automatically create a new coroutine for the scan,
which hands execution back to the original coroutine upon completion.
#### `parser:register_root_item(item: string | item_table, priority?: number): boolean`
A wrapper around [`fb.register_root_item`](#fbregister_root_itemitem-string--item_table-priority-number-boolean)
which uses the parser's priority value if `priority` is undefined.
#### `fb.remove_all_mappings(directory: string): string[]`
Removes all [directory mappings](#fbregister_directory_mappingdirectory-string--nil-mapping-string-pattern-bool-void)
that resolve to the given `directory`. Returns a list of the `mapping` strings
that were removed.
### Advanced Functions
#### `fb.clear_cache(): void`
Clears the directory cache. Use this if you are modifying the contents of directories other
than the current one to ensure that their contents will be rescanned when next opened.
#### `fb.coroutine.assert(err?: string): coroutine`
Throws an error if it is not called from within a coroutine. Returns the currently running coroutine on success.
The string argument can be used to throw a custom error string.
#### `fb.coroutine.callback(time_limit?: number): function`
Creates and returns a callback function that resumes the current coroutine.
This function is designed to help streamline asynchronous operations. The best way to explain is with an example:
```lua
local function execute(args)
mp.command_native_async({
name = "subprocess",
playback_only = false,
capture_stdout = true,
capture_stderr = true,
args = args
}, fb.coroutine.callback())
local _, cmd = coroutine.yield()
return cmd.status == 0 and cmd.stdout or nil
end
```
This function uses the mpv [subprocess](https://mpv.io/manual/master/#command-interface-subprocess)
command to execute some system operation. To prevent the whole script (file-browser and all addons) from freezing
it uses the [command_native_async](https://mpv.io/manual/master/#lua-scripting-mp-command-native-async(table-[,fn])) command
to execute the operation asynchronously and takes a callback function as its second argument.
`coroutine.callback())` will automatically create a callback function to resume whatever coroutine ran the `execute` function.
Any arguments passed into the callback function (by the async function, not by you) will be passed on to the resume;
in this case `command_native_async` passes three values into the callback, of which only the second is of interest to me.
If `time_limit` is set to a number, then a boolean is passed as the first resume argument to the coroutine.
If the callback is not run within `time_limit` seconds then the coroutine will be resumed, and the first
argument will be `false`. If the callback is run within the time limit then the first argument will be `true`.
```lua
local function execute(args)
local t = mp.command_native_async({
name = "subprocess",
playback_only = false,
capture_stdout = true,
capture_stderr = true,
args = args
}, fb.coroutine.callback(10))
local success, _, cmd = coroutine.yield()
if not success then
mp.abort_async_command(t)
msg.error("command timed out")
return nil
end
return cmd.status == 0 and cmd.stdout or nil
end
```
The expectation is that the programmer will yield execution before that callback returns. In this example I
yield immediately after running the async command.
If you are doing this during a parse operation you could also substitute `coroutine.yield()` with `parse_state:yield()` to abort the parse if the user changed
browser directories during the asynchronous operation.
If you have no idea what I've been talking about read the [Lua manual on coroutines](https://www.lua.org/manual/5.1/manual.html#2.11).
#### `fb.coroutine.resume_catch(co: coroutine, ...): (boolean, ...)`
Runs `coroutine.resume(co, ...)` with the given coroutine, passing through any additional arguments.
If the coroutine throws an error then an error message and stacktrace is printed to the console.
All the return values of `coroutine.resume` are caught and returned.
#### `fb.coroutine.resume_err(co: coroutine, ...): boolean`
Runs `coroutine.resume(co, ...)` with the given coroutine, passing through any additional arguments.
If the coroutine throws an error then an error message and stacktrace is printed to the console.
Returns the success boolean returned by `coroutine.resume`, but drops all other return values.
#### `fb.coroutine.run(fn: function, ...): void`
Runs the given function in a new coroutine, passing through any additional arguments.
#### `fb.coroutine.queue(fn: function, ...): coroutine`
Runs the given function in a coroutine when the script next goes idle, passing through
any additional arguments. The (not yet started) coroutine is returned by the function.
#### `fb.rescan(): coroutine`
Rescans the current directory. Equivalent to Ctrl+r without the cache refresh for higher level directories.
Returns the coroutine of the upcoming parse operation. The parse is queued and run when the script thread next goes idle,
allowing one to store this value and use it to identify the triggered parse operation.
#### `fb.redraw(): void`
Forces a redraw of the browser UI.
#### `parser:defer(directory: string): (list_table, opts_table) | nil`
Forwards the given directory to the next valid parser. For use from within a parse operation.
The `defer` function is very powerful, and can be used by scripts to create virtual directories, or to modify the results of other parsers.
However, due to how much freedom Lua gives coders, it is impossible for file-browser to ensure that parsers are using defer correctly, which can cause unexpected results.
The following are a list of recommendations that will increase the compatability with other parsers:
* Always return the opts table that is returned by defer, this can contain important values for file-browser, as described [above](#the-opts-table).
* If required modify values in the existing opts table, don't create a new one.
* Respect the `sorted` and `filtered` values in the opts table. This may mean calling `sort` or `filter` manually.
* Think about how to handle the `directory_label` field, especially how it might interract with any virtual paths the parser may be maintaining.
* Think about what to do if the `directory` field is set.
* Think if you want your parser to take full ownership of the results of `defer`, if so consider setting `opts.id = self:get_id()`.
* Currently this only affects custom keybind filtering, though it may be changed in the future.
The [home-label](https://github.com/CogentRedTester/mpv-file-browser/blob/master/addons/home-label.lua)
addon provides a good simple example of the safe use of defer. It lets the normal file
parser load the home directory, then modifies the directory label.
```lua
local mp = require "mp"
local fb = require "file-browser"
local home = fb.fix_path(mp.command_native({"expand-path", "~/"}), true)
local home_label = {
api_version = '1.0.0',
priority = 100
}
function home_label:can_parse(directory)
return directory:sub(1, home:len()) == home
end
function home_label:parse(directory, ...)
local list, opts = self:defer(directory, ...)
if (not opts.directory or opts.directory == directory) and not opts.directory_label then
opts.directory_label = "~/"..(directory:sub(home:len()+1) or "")
end
return list, opts
end
return home_label
```
### Utility Functions
#### `fb.ass_escape(str: string, substitute_newline?: true | string): string`
Returns the `str` string with escaped ass styling codes.
The optional 2nd argument allows replacing newlines with the given string, or `'\\n'` if set to `true`.
#### `fb.copy_table(t: table, depth?: number): table`
Returns a copy of table `t`.
The copy is done recursively to the given `depth`, and any cyclical table references are maintained.
Both keys and values are copied. If `depth` is undefined then it defaults to `math.huge` (infinity).
Additionally, the original table is stored in the `__original` field of the copy's metatable.
The copy behaviour of the metatable itself is subject to change, but currently it is not copied.
#### `fb.evaluate_string(str: string, chunkname?: string, env?: table, defaults?: bool = true): unknown`
Loads `str` as a chunk of Lua statement(s) and runs them, returning the result.
Errors are propagated to the caller. `chunkname` is used
for debug output and error messages.
Each chunk has a separate global environment table that inherits
from the main global table. This means new globals can be created safely,
but the default globals can still be accessed. As such, this method
cannot and should not be used for security or sandboxing.
A custom environment table can be provided with the `env` argument.
Inheritance from the global table is disabled if `defaults` is `false`.
Examples:
```lua
fb.evaluate_string('return 5 + 5') -- 10
fb.evaluate_string('x = 20 ; return x * x') -- 400
local code = [[
local arr = {1, 2, 3, 4}
table.insert(arr, x)
return unpack(arr)
]]
fb.evaluate_string(code, 'test3', {x = 5}) -- 1, 2, 3, 4, 5
fb.evaluate_string(code, 'test4', nil, false) -- Lua error: [string "test4"]:2: attempt to index global 'table' (a nil value)
```
In an expression the `mp`, `mp.msg`, and `mp.utils` modules are available as `mp`, `msg`, and `utils` respectively.
Additionally, in mpv v0.38+ the `mp.input` module is available as `input`.
This addon API is available as `fb` and if [mpv-user-input](https://github.com/CogentRedTester/mpv-user-input)
is installed then user-input will be available in `user_input`.
These modules are all unavailable if `defaults` is `false`.
#### `fb.filter(list: list_table): list_table`
Iterates through the given list and removes items that don't pass the user set filters
(dot files/directories and valid file extensions).
Returns the list but does not create a copy; the `list` table is filtered in-place.
#### `fb.fix_path(path: string, is_directory?: boolean): string`
Takes a path and returns a file-browser compatible path string.
The optional second argument is a boolean that tells the function to format the path to be a
directory.
#### `fb.get_extension(filename: string, def?: any): string | def`
Returns the file extension for the string `filename`, or `nil` if there is no extension.
If `def` is defined then that is returned instead of `nil`.
The full stop is not included in the extension, so `test.mkv` will return `mkv`.
#### `fb.get_full_path(item: item_table, directory?: string): string`
Takes an item table and returns the item's full path assuming it is in the given directory.
Takes into account `item.name`/`item.path` fields, etc.
If directory is nil then it uses the currently open directory.
#### `fb.get_protocol(url: string, def?: any): string | def`
Returns the protocol scheme for the string `url`, or `nil` if there is no scheme.
If `def` is defined then that is returned instead of `nil`.
The `://` is not included, so `https://example.com/test.mkv` will return `https`.
#### `fb.iterate_opt(opts: string): iterator`
Takes an options string consisting of a list of items separated by the `root_separators` defined in `file_browser.conf` and
returns an iterator function that can be used to iterate over each item in the list.
```lua
local opt = "a,b,zz z" -- root_separators=,
for item in fb.iterate_opt(opt) do
print(item) -- prints: 'a', 'b', 'zz z'
end
```
#### `fb.join_path(p1: string, p2: string): string`
A wrapper around [`mp.utils.join_path`](https://mpv.io/manual/master/#lua-scripting-utils-join-path(p1,-p2))
which treats paths with network protocols as absolute paths.
#### `fb.pattern_escape(str: string): string`
Returns `str` with Lua special pattern characters escaped.
#### `fb_utils.resolve_directory_mapping(path: string): string`
Takes a `path` string and resolves any
[directory mappings](#fbregister_directory_mappingdirectory-string--nil-mapping-string-pattern-bool-void),
replacing any substrings that match a mapping with the associated directory.
Only the first valid mapping is applied, but this behaviour will likely change in
the future. Changes to this behaviour will not consitute a major version bump so should not
be relied upon.
#### `fb.sort(list: list_table): list_table`
Iterates through the given list and sorts the items using file-browser's sorting algorithm.
Returns the list but does not create a copy; the `list` table is sorted in-place.
#### `fb.valid_file(name: string): boolean`
Tests if the string `name` passes the user set filters for valid files (extensions/dot files/etc).
#### `fb.valid_dir(name: string): boolean`
Tests if the string `name` passes the user set filters for valid directories (dot folders/etc).
### Getters
These functions allow addons to safely get information from file-browser.
All tables returned by these functions are copies sent through the [`fb.copy_table`](#fbcopy_tablet-table-depth-number-table)
function to ensure addons can't accidentally break things.
#### `fb.get_audio_extensions(): table`
Returns a set of extensions like [`fb.get_extensions`](#fbget_extensions-table) but for extensions that are opened
as additional audio tracks.
All of these are included in `fb.get_extensions`.
#### `fb.get_current_file(): table`
A table containing the path of the current open file in the form:
`{directory = "/home/me/", name = "bunny.mkv", path = "/home/me/bunny.mkv"}`.
#### `fb.get_current_parser(): string`
The unique id of the parser that successfully parsed the current directory.
#### `fb.get_current_parser_keyname(): string`
The `keybind_name` of the parser that successfully parsed the current directory.
Used for custom-keybind filtering.
#### `fb.get_directory(): string`
The current directory open in the browser.
#### `fb.get_dvd_device(): string`
The current dvd-device as reported by mpv's `dvd-device` property.
Formatted to work with file-browser.
#### `fb.get_extensions(): table`
Returns the set of valid extensions after applying the user's whitelist/blacklist options.
The table is in the form `{ mkv = true, mp3 = true, ... }`.
Sub extensions, audio extensions, and parseable extensions are all included in this set.
#### `fb.get_list(): list_table`
The list_table currently open in the browser.
#### `fb.get_open_status(): boolean`
Returns true if the browser is currently open and false if not.
#### `fb.get_opt(name: string): string | number | boolean`
Returns the script-opt with the given name.
#### `fb.get_parsers(): table`
Returns a table of all the loaded parsers/addons.
The formatting of this table in undefined, but it should
always contain an array of the parsers in order of priority.
#### `fb.get_parse_state(co?: coroutine): parse_state_table`
Returns the [parse_state table](#parse-state-table) for the given coroutine.
If no coroutine is given then it uses the running coroutine.
Every parse operation is guaranteed to have a unique coroutine.
#### `fb.get_parseable_extensions(): table`
Returns a set of extensions like [`fb.get_extensions`](#fbget_extensions-table) but for extensions that are
treated as parseable by the browser.
All of these are included in `fb.get_extensions`.
#### `fb.get_root(): list_table`
Returns the root table.
#### `fb.get_script_opts(): table`
The table of script opts set by the user. This currently does not get
changed during runtime, but that is not guaranteed for future minor version increments.
#### `fb.get_selected_index(): number`
The current index of the cursor.
Note that it is possible for the cursor to be outside the bounds of the list;
for example when the list is empty this usually returns 1.
#### `fb.get_selected_item(): item_table | nil`
Returns the item_table of the currently selected item.
If no item is selected (for example an empty list) then returns nil.
#### `fb.get_state(): table`
Returns the current state values of the browser.
These are not documented and are subject to change at any time,
adding a proper getter for anything is a valid request.
#### `fb.get_sub_extensions(): table`
Returns a set of extensions like [`fb.get_extensions`](#fbget_extensions-table) but for extensions that are opened
as additional subtitle tracks.
All of these are included in `fb.get_extensions`.
#### `parser:get_id(): string`
The unique id of the parser. Used for log messages and various internal functions.
#### `parser:get_index(): number`
The index of the parser in order of preference (based on the priority value).
`defer` uses this internally.
### Setters
#### `fb.set_selected_index(pos: number): number | false`
Sets the cursor position and returns the new index.
If the input is not a number return false, if the input is out of bounds move it in bounds.
## Examples
For standard addons that add support for non-native filesystems, but otherwise don't do anything fancy, see [ftp-browser](ftp-browser.lua) and [apache-browser](apache-browser.lua).
For more simple addons that make a few small modifications to how other parsers are displayed, see [home-label](home-label.lua).
For more complex addons that maintain their own virtual directory structure, see
[favourites](favourites.lua).

View File

@@ -1,330 +0,0 @@
# Custom Keybinds
File-browser also supports custom keybinds. These keybinds send normal input commands, but the script will substitute characters in the command strings for specific values depending on the currently open directory, and currently selected item.
This allows for a wide range of customised behaviour, such as loading additional audio tracks from the browser, or copying the path of the selected item to the clipboard.
The feature is disabled by default, but is enabled with the `custom_keybinds` script-opt.
Keybinds are declared in the `~~/script-opts/file-browser-keybinds.json` file, the config takes the form of an array of json objects, with the following keys:
| option | required | default | description |
|---------------|----------|------------|--------------------------------------------------------------------------------------------|
| key | yes | - | the key to bind the command to - same syntax as input.conf |
| command | yes | - | json array of commands and arguments |
| name | no | numeric id | name of the script-binding - see [modifying default keybinds](#modifying-default-keybinds) |
| condition | no | - | a Lua [expression](#expressions) - the keybind will only run if this evaluates to true |
| flags | no | - | flags to send to the mpv add_keybind function - see [here](https://mpv.io/manual/master/#lua-scripting-[,flags]]\)) |
| filter | no | - | run the command on just a file (`file`) or folder (`dir`) |
| parser | no | - | run the command only in directories provided by the specified parser. |
| multiselect | no | `false` | command is run on all selected items |
| multi-type | no | `repeat` | which multiselect mode to use - `repeat` or `concat` |
| delay | no | `0` | time to wait between sending repeated multi commands |
| concat-string | no | `' '` (space) | string to insert between items when concatenating multi commands |
| passthrough | no | - | force or ban passthrough behaviour - see [passthrough](#passthrough-keybinds) |
| api_version | no | - | tie the keybind to a particular [addon API version](./addons.md#api-version), printing warnings and throwing errors if the keybind is used with wrong versions |
Example:
```json
{
"key": "KP1",
"command": ["print-text", "example"],
}
```
The command can also be an array of arrays, in order to send multiple commands at once:
```json
{
"key": "KP2",
"command": [
["print-text", "example2"],
["show-text", "example2"]
]
}
```
Filter should not be included unless one wants to limit what types of list entries the command should be run on.
To only run the command for directories use `dir`, to only run the command for files use `file`.
The parser filter is for filtering keybinds to only work inside directories loaded by specific parsers.
There are two parsers in the base script, the default parser for native filesystems is called `file`, while the root parser is called `root`.
Other parsers can be supplied by addons, and use the addon's filename with `-browser.lua` or just `.lua` stripped unless otherwise stated.
For example `ftp-browser.lua` would have a parser called `ftp`.
You can set the filter to match multiple parsers by separating the names with spaces.
```json
{
"key": "KP2",
"command": [ ["print-text", "example3"] ],
"parser": "ftp file"
}
```
The `flags` field is mostly only useful for addons, but can also be useful if one wants a key to be repeatable.
In this case the the keybind would look like the following:
```json
{
"key": "p",
"command": ["print-text", "spam-text"],
"flags": { "repeatable": true }
}
```
## Codes
The script will scan every string in the command for the special substitution strings, they are:
| code | description |
|--------|---------------------------------------------------------------------|
| `%%` | escape code for `%` |
| `%f` | filepath of the selected item |
| `%n` | filename of the selected item |
| `%p` | currently open directory |
| `%q` | currently open directory but preferring the directory label |
| `%d` | name of the current directory (characters between the last two '/') |
| `%r` | name of the parser for the currently open directory |
| `%x` | number of items in the currently open directory |
| `%i` | the 1-based index of the selected item in the list |
| `%j` | the 1-based index of the item in a multiselection - returns 1 for single selections |
Additionally, using the uppercase forms of those codes will send the substituted string through the `string.format("%q", str)` function.
This adds double quotes around the string and automatically escapes any characters which would break the string encapsulation.
This is not necessary for most mpv commands, but can be very useful when sending commands to the OS with the `run` command,
or when passing values into [expressions](#conditional-command-condition-command).
Example of a command to add an audio track:
```json
{
"key": "Ctrl+a",
"command": ["audio-add", "%f"],
"filter": "file"
}
```
Any commands that contain codes representing specific items (`%f`, `%n`, `%i` etc) will
not be run if no item is selected (for example in an empty directory).
In these cases [passthrough](#passthrough-keybinds) rules will apply.
## Multiselect Commands
When multiple items are selected the command can be run for all items in the order they appear on the screen.
This can be controlled by the `multiselect` flag, which takes a boolean value.
When not set the flag defaults to `false`.
There are two different multiselect modes, controlled by the `multi-type` option. There are two options:
### `repeat`
The default mode that sends the commands once for each item that is selected.
If time is needed between running commands of multiple selected items (for example, due to file handlers) then the `delay` option can be used to set a duration (in seconds) between commands.
### `concat`
Run a single command, but replace item specific codes with a concatenated string made from each selected item.
For example `["print-text", "%n" ]` would print the name of each item selected separated by `' '` (space).
The string inserted between each item is determined by the `concat-string` option, but `' '` is the default.
## Passthrough Keybinds
When loading keybinds from the json file file-browser will move down the list and overwrite any existing bindings with the same key.
This means the lower an item on the list, the higher preference it has.
However, file-browser implements a layered passthrough system for its keybinds; if a keybind is blocked from running by user filters, then the next highest preference command will be sent, continuing until a command is sent or there are no more keybinds.
The default dynamic keybinds are considered the lowest priority.
The `filter`, `parser`, and `condition` options can all trigger passthrough, as well as some [codes](#codes).
If a multi-select command is run on multiple items then passthrough will occur if any of the selected items fail the filters.
Passthrough can be forcibly disabled or enabled using the passthrough option.
When set to `true` passthrough will always be activate regardless of the state of the filters.
## Modifying Default Keybinds
Since the custom keybinds are applied after the default dynamic keybinds they can be used to overwrite the default bindings.
Setting new keys for the existing binds can be done with the `script-binding [binding-name]` command, where `binding-name` is the full name of the keybinding.
For this script the names of the dynamic keybinds are in the format `file_browser/dynamic/[name]` where `name` is a unique identifier documented in the [keybinds](README.md#keybinds) table.
For example to change the scroll buttons from the arrows to the scroll wheel:
```json
[
{
"key": "WHEEL_UP",
"command": ["script-binding", "file_browser/dynamic/scroll_up"]
},
{
"key": "WHEEL_DOWN",
"command": ["script-binding", "file_browser/dynamic/scroll_down"]
},
{
"key": "UP",
"command": ["osd-auto", "add", "volume", "2"]
},
{
"key": "DOWN",
"command": ["osd-auto", "add", "volume", "-2"]
}
]
```
Custom keybinds can be called using the same method, but users must set the `name` value inside the `file-browser-keybinds.json` file.
To avoid conflicts custom keybinds use the format: `file_browser/dynamic/custom/[name]`.
## Expressions
Expressions are used to evaluate Lua code into a string that can be used for commands.
These behave similarly to those used for [`profile-cond`](https://mpv.io/manual/master/#conditional-auto-profiles)
values. In an expression the `mp`, `mp.msg`, and `mp.utils` modules are available as `mp`, `msg`, and `utils` respectively.
Additionally, in mpv v0.38+ the `mp.input` module is available as `input`.
The file-browser [addon API](addons/addons.md#the-api) is available as `fb` and if [mpv-user-input](https://github.com/CogentRedTester/mpv-user-input)
is installed then user-input API will be available in `user_input`.
This example only runs the keybind if the browser is in the Windows C drive or if
the selected item is a matroska file:
```json
[
{
"key": "KP1",
"command": ["print-text", "in my C:/ drive!"],
"condition": "(%P):find('C:/') == 1"
},
{
"key": "KP2",
"command": ["print-text", "Matroska File!"],
"condition": "fb.get_extension(%N) == 'mkv'"
}
]
```
If the `condition` expression contains any item specific codes (`%F`, `%I`, etc) then it will be
evaluated on each individual item, otherwise it will evaluated once for the whole keybind.
If a code is invalid (for example using `%i` in empty directories) then the expression returns false.
There are some utility script messages that extend the power of expressions.
[`conditional-command`](#conditional-command-condition-command) allows one to specify conditions that
can apply to individual items or commands. The tradeoff is that you lose the automated passthrough behaviour.
There is also [`evaluate-expressions`](#evaluate-expressions-command) which allows one to evaluate expressions inside commands.
## Utility Script Messages
There are a small number of custom script messages defined by file-browser to support custom keybinds.
### `=> <command...>`
A basic script message that makes it easier to chain multiple utility script messages together.
Any `=>` string will be substituted for `script-message`.
```json
{
"key": "KP1",
"command": ["script-message", "=>", "delay-command", "%j * 2", "=>", "evaluate-expressions", "print-text", "!{%j * 2}"],
"multiselect": true
}
```
### `conditional-command [condition] <command...>`
Runs the following command only if the condition [expression](#expressions) is `true`.
This example command will only run if the player is currently paused:
```json
{
"key": "KP1",
"command": ["script-message", "conditional-command", "mp.get_property_bool('pause')", "print-text", "is paused"],
}
```
Custom keybind codes are evaluated before the expressions.
This example only runs if the currently selected item in the browser has a `.mkv` extension:
```json
{
"key": "KP1",
"command": ["script-message", "conditional-command", "fb.get_extension(%N) == 'mkv'", "print-text", "a matroska file"],
}
```
### `delay-command [delay] <command...>`
Delays the following command by `[delay]` seconds.
Delay is an [expression](#expressions).
The following example will send the `print-text` command after 5 seconds:
```json
{
"key": "KP1",
"command": ["script-message", "delay-command", "5", "print-text", "example"],
}
```
### `evaluate-expressions <command...>`
Evaluates embedded Lua expressions in the following command.
Expressions have the same behaviour as the [`conditional-command`](#conditional-command-condition-command) script-message.
Expressions must be surrounded by `!{}` characters.
Additional `!` characters can be placed at the start of the expression to
escape the evaluation.
For example the following keybind will print 3 to the console:
```json
{
"key": "KP1",
"command": ["script-message", "evaluate-expressions", "print-text", "!{1 + 2}"],
}
```
This example replaces all `/` characters in the path with `\`
(note that the `\` needs to be escaped twice, once for the json file, and once for the string in the lua expression):
```json
{
"key": "KP1",
"command": ["script-message", "evaluate-expressions", "print-text", "!{ string.gsub(%F, '/', '\\\\') }"],
}
```
### `run-statement <statement...>`
Runs the following string a as a Lua statement. This is similar to an [expression](#expressions),
but instead of the code evaluating to a value it must run a series of statements. Basically it allows
for function bodies to be embedded into custom keybinds. All the same modules are available.
If multiple strings are sent to the script-message then they will be concatenated together with newlines.
The following keybind will use [mpv-user-input](https://github.com/CogentRedTester/mpv-user-input) to
rename items in file-browser:
```json
{
"key": "KP1",
"command": ["script-message", "run-statement",
"assert(user_input, 'install mpv-user-input!')",
"local line, err = user_input.get_user_input_co({",
"id = 'rename-file',",
"source = 'custom-keybind',",
"request_text = 'rename file:',",
"queueable = true,",
"default_input = %N,",
"cursor_pos = #(%N) - #fb.get_extension(%N, '')",
"})",
"if not line then return end",
"os.rename(%F, utils.join_path(%P, line))",
"fb.rescan()"
],
"parser": "file",
"multiselect": true
}
```
## Examples
See [here](file-browser-keybinds.json).

View File

@@ -1,118 +0,0 @@
[
{
"key": "KP1",
"command": ["print-text", "file: %f"],
"multiselect": true
},
{
"key": "KP2",
"command": ["print-text", "name: %n"],
"multiselect": true
},
{
"key": "KP3",
"command": ["print-text", "open directory: %p"]
},
{
"key": "KP4",
"command": ["print-text", "directory name: %d"]
},
{
"key": "KP5",
"command": ["print-text", "escape the code: %%f"],
"multiselect": true
},
{
"key": "KP6",
"command": ["print-text", "full filepath via concatenation: %p%n"],
"multiselect": true
},
{
"key": "KP7",
"command": ["print-text", "quote/escape filepath: %F"],
"multiselect": true
},
{
"comment": "deletes the currently selected file",
"key": "Alt+DEL",
"command": ["run", "rm", "%F"],
"filter": "file",
"multiselect": true,
"multi-type": "concat"
},
{
"comment": "opens the currently selected items in a new mpv window",
"key": "Ctrl+ENTER",
"command": ["run", "mpv", "%F"],
"multiselect": true,
"multi-type": "concat"
},
{
"key": "Ctrl+c",
"command": [
["run", "powershell", "-command", "Set-Clipboard", "%F"],
["print-text", "copied filepath to clipboard"]
],
"multiselect": true,
"delay": 0.3
},
{
"comment": "Opens the current directory in windows explorer",
"key": "Ctrl+o",
"command": ["run", "powershell", "-command", "explorer.exe", "(( %P ).TrimEnd('/') -replace '/', '\\' )"],
"multiselect": false
},
{
"comment": "Opens the selected directory in windows explorer",
"key": "Ctrl+O",
"command": ["run", "powershell", "-command", "explorer.exe", "(( %F ).TrimEnd('/') -replace '/', '\\' )"],
"filter": "dir",
"multiselect": true
},
{
"comment": "Opens the current directory in windows explorer and highlights the currently selected file",
"key": "Ctrl+O",
"command": ["run", "powershell", "-command", "explorer.exe", "'/select,'", "( %F -replace '/', '\\' )"],
"filter": "file",
"multiselect": true
},
{
"key": "INS",
"command": ["run", "powershell", "-command", "Set-Content", "-LiteralPath", "( %P + '/.ordered-chapters.m3u' )", "-Value", "( %N )"],
"multiselect": true,
"multi-type": "concat",
"concat-string": "+ '\n' +"
},
{
"key": "WHEEL_UP",
"command": ["script-binding", "file_browser/dynamic/scroll_up"]
},
{
"key": "WHEEL_DOWN",
"command": ["script-binding", "file_browser/dynamic/scroll_down"]
},
{
"key": "MBTN_LEFT",
"command": ["script-binding", "file_browser/dynamic/down_dir"]
},
{
"key": "MBTN_RIGHT",
"command": ["script-binding", "file_browser/dynamic/up_dir"]
},
{
"key": "MBTN_MID",
"command": ["script-binding", "file_browser/dynamic/play"]
},
{
"key": "UP",
"command": ["osd-auto", "add", "volume", "2"]
},
{
"key": "DOWN",
"command": ["osd-auto", "add", "volume", "-2"]
}
]

View File

@@ -1,175 +0,0 @@
#######################################################
# This is the default config file for mpv-file-browser
# https://github.com/CogentRedTester/mpv-file-browser
#######################################################
# root directories, separated by commas
# on linux you will probably want to add `/`,
# on windows this should be used to add different drive letters
# Examples:
# linux: root=~/,/
# windows: root=~/,C:/
root=~/
# characters to separate root directories, each character works individually
# this is in case one is using directories with strange names
root_separators=,;
# number of entries to show on the screen at once
num_entries=20
# wrap the cursor around the top and bottom of the list
wrap=no
# only show files compatible with mpv in the browser
filter_files=yes
# experimental feature that recurses directories concurrently when appending items to the playlist
# this feature has the potential for massive performance improvements when using addons with asynchronous IO
concurrent_recursion=no
# maximum number of recursions that can run concurrently
# if this number is too high it risks overflowing the mpv event queue, which will cause some directories to be dropped entirely
max_concurrency=16
# enable custom keybinds
# the keybind json file must go in ~~/script-opts
custom_keybinds=no
# file-browser only shows files that are compatible with mpv by default
# adding a file extension to this list will add it to the extension whitelist
# extensions are separated with the root separators, do not use any spaces
extension_whitelist=
# add file extensions to this list to disable default filetypes
# note that this will also override audio/subtitle_extension options below
extension_blacklist=
# files with these extensions will be added as additional audio tracks for the current file instead of appended to the playlist
# items on this list are automatically added to the extension whitelist
audio_extensions=mka,dts,dtshd,dts-hd,truehd,true-hd
# files with these extensions will be added as additional subtitle tracks for the current file instead of appended to the playlist
# items on this list are automatically added to the extension whitelist
subtitle_extensions=etf,etf8,utf-8,idx,sub,srt,rt,ssa,ass,mks,vtt,sup,scc,smi,lrc,pgs
# filter directories or files starting with a period like .config
# for linux systems
filter_dot_dirs=no
filter_dot_files=no
# substitude forward slashes for backslashes when appending a local file to the playlist
# may be useful on windows systems
substitute_backslash=no
# interpret backslashes `\` in paths as forward slashes `/`
# this is useful on Windows, which natively uses backslashes.
# As backslashes are valid filename characters in Unix systems this could
# cause mangled paths, though such filenames are rare.
# Use `yes` and `no` to enable/disable. `auto` tries to use the mpv `platform`
# property (mpv v0.36+) to decide. If the property is unavailable it defaults to `yes`.
normalise_backslash=auto
# this option reverses the behaviour of the alt+ENTER keybind
# when disabled the keybind is required to enable autoload for the file
# when enabled the keybind disables autoload for the file
autoload=no
# if autoload is triggered by selecting the currently playing file, then
# the current file will have it's watch-later config saved before being closed and re-opened
# essentially the current file will not be restarted
autoload_save_current=yes
# when opening the browser in idle mode prefer the current working directory over the root
# note that the working directory is set as the 'current' directory regardless, so `home` will
# move the browser there even if this option is set to false
default_to_working_directory=no
# when moving up a directory do not stop on empty protocol schemes like `ftp://`
# e.g. moving up from `ftp://localhost/` will move straight to the root instead of `ftp://`
skip_protocol_schemes=yes
# map optical device paths to their respective file paths,
# e.g. mapping bd:// to the value of the bluray-device property
map_bd_device=yes
map_dvd_device=yes
map_cdda_device=yes
# enables addons
addons=no
addon_directory=~~/script-modules/file-browser-addons
# directory to load external modules - currently just user-input-module
module_directory=~~/script-modules
# turn the OSC idle screen off and on when opening and closing the browser
# this should only be enabled if file-browser is the only thing controlling the idle-screen,
# if multiple sources attempt to control the idle-screen at the same time it can cause unexpected behaviour.
toggle_idlescreen=no
# Set the current open status of the browser in the `file_browser/open` field of the `user-data` property.
# This property is only available in mpv v0.36+.
set_user_data=yes
# Set the current open status of the browser in the `file_browser-open` field of the `shared-script-properties` property.
# This property is deprecated. When it is removed in mpv v0.37 file-browser will automatically disable this option.
set_shared_script_properties=no
####################################
######### style settings ###########
####################################
# force file-browser to use a specific text alignment (default: top-left)
# uses ass tag alignment numbers: https://aegi.vmoe.info/docs/3.0/ASS_Tags/#index23h3
# set to 0 to use the default mpv osd-align options
alignment=7
# The format string used for the header. Uses custom-keybind substitution codes to
# dynamically change the contents of the header. See: docs/custom-keybinds.md#codes
# e.g. to add file numbers, set this to: {\fnMonospace}[%i/%x]{\fn<font_name_header or blank>} %q\N----------------------------------------------------
format_string_header=%q\N----------------------------------------------------
# The format strings used for the wrappers. Supports custom-keybind substitution codes, and
# supports two additional codes: `%<` and `%>` to show the number of items before and after the visible list, respectively.
# Setting these options to empty strings will disable the wrappers.
format_string_topwrapper=%< item(s) above\N
format_string_bottomwrapper=\N%> item(s) remaining
# allows custom icons be set for the folder and cursor
# the `\h` character is a hard space to add padding
folder_icon={\p1}m 6.52 0 l 1.63 0 b 0.73 0 0.01 0.73 0.01 1.63 l 0 11.41 b 0 12.32 0.73 13.05 1.63 13.05 l 14.68 13.05 b 15.58 13.05 16.31 12.32 16.31 11.41 l 16.31 3.26 b 16.31 2.36 15.58 1.63 14.68 1.63 l 8.15 1.63{\p0}\h
cursor_icon={\p1}m 14.11 6.86 l 0.34 0.02 b 0.25 -0.02 0.13 -0 0.06 0.08 b -0.01 0.16 -0.02 0.28 0.04 0.36 l 3.38 5.55 l 3.38 5.55 3.67 6.15 3.81 6.79 3.79 7.45 3.61 8.08 3.39 8.5l 0.04 13.77 b -0.02 13.86 -0.01 13.98 0.06 14.06 b 0.11 14.11 0.17 14.13 0.24 14.13 b 0.27 14.13 0.31 14.13 0.34 14.11 l 14.11 7.28 b 14.2 7.24 14.25 7.16 14.25 7.07 b 14.25 6.98 14.2 6.9 14.11 6.86{\p0}\h
# set the opacity of fonts in hexadecimal from 00 (opaque) to FF (transparent)
font_opacity_selection_marker=99
# print the header in bold font
font_bold_header=yes
# scale the size of the browser; 2 would double the size, 0.5 would halve it, etc.
# the header and wrapper scaling is relative to the base scaling
scaling_factor_base=1
scaling_factor_header=1.4
scaling_factor_wrappers=0.64
# set custom font names, blank is the default
# setting custom fonts for the folder/cursor can fix broken or missing icons
font_name_header=
font_name_body=
font_name_wrappers=
font_name_folder=
font_name_cursor=
# set custom font colours
# colours are in hexadecimal format in Blue Green Red order
# note that this is the opposite order to most RGB colour codes
font_colour_header=00ccff
font_colour_body=ffffff
font_colour_wrappers=00ccff
font_colour_cursor=00ccff
# these are colours applied to list items in different states
font_colour_selected=fce788
font_colour_multiselect=fcad88
font_colour_playing=33ff66
font_colour_playing_multiselected=22b547

View File

@@ -1,73 +0,0 @@
--[[
mpv-file-browser
This script allows users to browse and open files and folders entirely from within mpv.
The script uses nothing outside the mpv API, so should work identically on all platforms.
The browser can move up and down directories, start playing files and folders, or add them to the queue.
For full documentation see: https://github.com/CogentRedTester/mpv-file-browser
]]--
local mp = require 'mp'
local o = require 'modules.options'
-- setting the package paths
package.path = mp.command_native({"expand-path", o.module_directory}).."/?.lua;"..package.path
local addons = require 'modules.addons'
local keybinds = require 'modules.keybinds'
local setup = require 'modules.setup'
local controls = require 'modules.controls'
local observers = require 'modules.observers'
local script_messages = require 'modules.script-messages'
local input_loaded, input = pcall(require, "mp.input")
local user_input_loaded, user_input = pcall(require, "user-input-module")
-- root and addon setup
setup.root()
addons.load_internal_parsers()
if o.addons then addons.load_external_addons() end
--these need to be below the addon setup in case any parsers add custom entries
setup.extensions_list()
keybinds.setup_keybinds()
-- property observers
mp.observe_property('path', 'string', observers.current_directory)
if o.map_dvd_device then mp.observe_property('dvd-device', 'string', observers.dvd_device) end
if o.map_bd_device then mp.observe_property('bluray-device', 'string', observers.bd_device) end
if o.map_cdda_device then mp.observe_property('cdda-device', 'string', observers.cd_device) end
-- scripts messages
mp.register_script_message('=>', script_messages.chain)
mp.register_script_message('delay-command', script_messages.delay_command)
mp.register_script_message('conditional-command', script_messages.conditional_command)
mp.register_script_message('evaluate-expressions', script_messages.evaluate_expressions)
mp.register_script_message('run-statement', script_messages.run_statement)
mp.register_script_message('browse-directory', controls.browse_directory)
mp.register_script_message("get-directory-contents", script_messages.get_directory_contents)
--declares the keybind to open the browser
mp.add_key_binding('MENU','browse-files', controls.toggle)
mp.add_key_binding('Ctrl+o','open-browser', controls.open)
if input_loaded then
mp.add_key_binding("Alt+o", "browse-directory/get-user-input", function()
input.get({
prompt = "open directory:",
id = "file-browser/browse-directory",
submit = function(text)
controls.browse_directory(text)
input.terminate()
end
})
end)
elseif user_input_loaded then
mp.add_key_binding("Alt+o", "browse-directory/get-user-input", function()
user_input.get_user_input(controls.browse_directory, {request_text = "open directory:"})
end)
end

View File

@@ -1,174 +0,0 @@
local mp = require 'mp'
local msg = require 'mp.msg'
local utils = require 'mp.utils'
local o = require 'modules.options'
local g = require 'modules.globals'
local fb = require 'modules.apis.fb'
local fb_utils = require 'modules.utils'
local parser_API = require 'modules.apis.parser'
local API_MAJOR, API_MINOR, API_PATCH = g.API_VERSION:match("(%d+)%.(%d+)%.(%d+)")
API_MAJOR, API_MINOR, API_PATCH = tonumber(API_MAJOR), tonumber(API_MINOR), tonumber(API_PATCH)
--checks if the given parser has a valid version number
local function check_api_version(parser, id)
if parser.version then
msg.warn(('%s: use of the `version` field is deprecated - use `api_version` instead'):format(id))
parser.api_version = parser.version
end
local version = parser.api_version
if type(version) ~= 'string' then return msg.error(("%s: field `api_version` must be a string, got %s"):format(id, tostring(version))) end
local major, minor = version:match("(%d+)%.(%d+)")
major, minor = tonumber(major), tonumber(minor)
if not major or not minor then
return msg.error(("%s: invalid version number, expected v%d.%d.x, got v%s"):format(id, API_MAJOR, API_MINOR, version))
elseif major ~= API_MAJOR then
return msg.error(("%s has wrong major version number, expected v%d.x.x, got, v%s"):format(id, API_MAJOR, version))
elseif minor > API_MINOR then
msg.warn(("%s has newer minor version number than API, expected v%d.%d.x, got v%s"):format(id, API_MAJOR, API_MINOR, version))
end
return true
end
--create a unique id for the given parser
local function set_parser_id(parser)
local name = parser.name
if g.parsers[name] then
local n = 2
name = parser.name.."_"..n
while g.parsers[name] do
n = n + 1
name = parser.name.."_"..n
end
end
g.parsers[name] = parser
g.parsers[parser] = { id = name }
end
--runs an addon in a separate environment
local function run_addon(path)
local name_sqbr = string.format("[%s]", path:match("/([^/]*)%.lua$"))
local addon_environment = fb_utils.redirect_table(_G)
addon_environment._G = addon_environment
--gives each addon custom debug messages
addon_environment.package = fb_utils.redirect_table(addon_environment.package)
addon_environment.package.loaded = fb_utils.redirect_table(addon_environment.package.loaded)
local msg_module = {
log = function(level, ...) msg.log(level, name_sqbr, ...) end,
fatal = function(...) return msg.fatal(name_sqbr, ...) end,
error = function(...) return msg.error(name_sqbr, ...) end,
warn = function(...) return msg.warn(name_sqbr, ...) end,
info = function(...) return msg.info(name_sqbr, ...) end,
verbose = function(...) return msg.verbose(name_sqbr, ...) end,
debug = function(...) return msg.debug(name_sqbr, ...) end,
trace = function(...) return msg.trace(name_sqbr, ...) end,
}
addon_environment.print = msg_module.info
addon_environment.require = function(module)
if module == "mp.msg" then return msg_module end
return require(module)
end
local chunk, err
if setfenv then
--since I stupidly named a function loadfile I need to specify the global one
--I've been using the name too long to want to change it now
chunk, err = _G.loadfile(path)
if not chunk then return msg.error(err) end
setfenv(chunk, addon_environment)
else
chunk, err = _G.loadfile(path, "bt", addon_environment)
if not chunk then return msg.error(err) end
end
local success, result = xpcall(chunk, fb_utils.traceback)
return success and result or nil
end
--setup an internal or external parser
local function setup_parser(parser, file)
parser = setmetatable(parser, { __index = parser_API })
parser.name = parser.name or file:gsub("%-browser%.lua$", ""):gsub("%.lua$", "")
set_parser_id(parser)
if not check_api_version(parser, file) then return msg.error("aborting load of parser", parser:get_id(), "from", file) end
msg.verbose("imported parser", parser:get_id(), "from", file)
--sets missing functions
if not parser.can_parse then
if parser.parse then parser.can_parse = function() return true end
else parser.can_parse = function() return false end end
end
if parser.priority == nil then parser.priority = 0 end
if type(parser.priority) ~= "number" then return msg.error("parser", parser:get_id(), "needs a numeric priority") end
table.insert(g.parsers, parser)
end
--load an external addon
local function setup_addon(file, path)
if file:sub(-4) ~= ".lua" then return msg.verbose(path, "is not a lua file - aborting addon setup") end
local addon_parsers = run_addon(path)
if addon_parsers and not next(addon_parsers) then return msg.verbose('addon', path, 'returned empry table - special case, ignoring') end
if not addon_parsers or type(addon_parsers) ~= "table" then return msg.error("addon", path, "did not return a table") end
--if the table contains a priority key then we assume it isn't an array of parsers
if not addon_parsers[1] then addon_parsers = {addon_parsers} end
for _, parser in ipairs(addon_parsers) do
setup_parser(parser, file)
end
end
--loading external addons
local function load_addons(directory)
directory = fb_utils.fix_path(directory, true)
local files = utils.readdir(directory)
if not files then error("could not read addon directory") end
for _, file in ipairs(files) do
setup_addon(file, directory..file)
end
table.sort(g.parsers, function(a, b) return a.priority < b.priority end)
--we want to store the indexes of the parsers
for i = #g.parsers, 1, -1 do g.parsers[ g.parsers[i] ].index = i end
--we want to run the setup functions for each addon
for index, parser in ipairs(g.parsers) do
if parser.setup then
local success = xpcall(function() parser:setup() end, fb_utils.traceback)
if not success then
msg.error("parser", parser:get_id(), "threw an error in the setup method - removing from list of parsers")
table.remove(g.parsers, index)
end
end
end
end
local function load_internal_parsers()
local internal_addon_dir = mp.get_script_directory()..'/modules/parsers/'
load_addons(internal_addon_dir)
end
local function load_external_addons()
local addon_dir = mp.command_native({"expand-path", o.addon_directory..'/'})
load_addons(addon_dir)
end
return {
check_api_version = check_api_version,
load_internal_parsers = load_internal_parsers,
load_external_addons = load_external_addons
}

View File

@@ -1,136 +0,0 @@
local msg = require 'mp.msg'
local utils = require 'mp.utils'
local o = require 'modules.options'
local g = require 'modules.globals'
local fb_utils = require 'modules.utils'
local ass = require 'modules.ass'
local directory_movement = require 'modules.navigation.directory-movement'
local scanning = require 'modules.navigation.scanning'
local cache = require 'modules.cache'
local controls = require 'modules.controls'
local fb = setmetatable({}, { __index = setmetatable({}, { __index = fb_utils }) })
package.loaded["file-browser"] = setmetatable({}, { __index = fb })
--these functions we'll provide as-is
fb.redraw = ass.update_ass
fb.rescan = scanning.rescan
fb.browse_directory = controls.browse_directory
function fb.clear_cache()
cache:clear()
end
--a wrapper around scan_directory for addon API
function fb.parse_directory(directory, parse_state)
if not parse_state then parse_state = { source = "addon" }
elseif not parse_state.source then parse_state.source = "addon" end
return scanning.scan_directory(directory, parse_state)
end
--register file extensions which can be opened by the browser
function fb.register_parseable_extension(ext)
g.parseable_extensions[string.lower(ext)] = true
end
function fb.remove_parseable_extension(ext)
g.parseable_extensions[string.lower(ext)] = nil
end
--add a compatible extension to show through the filter, only applies if run during the setup() method
function fb.add_default_extension(ext)
table.insert(g.compatible_file_extensions, ext)
end
--add item to root at position pos
function fb.insert_root_item(item, pos)
msg.debug("adding item to root", item.label or item.name, pos)
item.ass = item.ass or fb.ass_escape(item.label or item.name)
item.type = "dir"
table.insert(g.root, pos or (#g.root + 1), item)
end
-- add a new mapping to the given directory
function fb.register_directory_mapping(directory, mapping, pattern)
if not pattern then mapping = '^'..fb_utils.pattern_escape(mapping) end
g.directory_mappings[mapping] = directory
msg.verbose('registering directory alias', mapping, directory)
directory_movement.set_current_file(g.current_file.original_path)
return mapping
end
-- remove all directory mappings that map to the given directory
function fb.remove_all_mappings(directory)
local removed = {}
for mapping, target in pairs(g.directory_mappings) do
if target == directory then
g.directory_mappings[mapping] = nil
table.insert(removed, mapping)
end
end
return removed
end
--a newer API for adding items to the root
--only adds the item if the same item does not already exist in the root
--the priority variable is a number that specifies the insertion location
--a lower priority is placed higher in the list and the default is 100
function fb.register_root_item(item, priority)
msg.verbose('registering root item:', utils.to_string(item))
if type(item) == 'string' then
item = {name = item}
end
-- if the item is already in the list then do nothing
if fb.list.some(g.root, function(r)
return fb.get_full_path(r, '') == fb.get_full_path(item, '')
end) then return false end
item._priority = priority
for i, v in ipairs(g.root) do
if (v._priority or 100) > (priority or 100) then
fb.insert_root_item(item, i)
return true
end
end
fb.insert_root_item(item)
return true
end
--providing getter and setter functions so that addons can't modify things directly
function fb.get_script_opts() return fb.copy_table(o) end
function fb.get_opt(key) return o[key] end
function fb.get_extensions() return fb.copy_table(g.extensions) end
function fb.get_sub_extensions() return fb.copy_table(g.sub_extensions) end
function fb.get_audio_extensions() return fb.copy_table(g.audio_extensions) end
function fb.get_parseable_extensions() return fb.copy_table(g.parseable_extensions) end
function fb.get_state() return fb.copy_table(g.state) end
function fb.get_dvd_device() return g.dvd_device end
function fb.get_parsers() return fb.copy_table(g.parsers) end
function fb.get_root() return fb.copy_table(g.root) end
function fb.get_directory() return g.state.directory end
function fb.get_list() return fb.copy_table(g.state.list) end
function fb.get_current_file() return fb.copy_table(g.current_file) end
function fb.get_current_parser() return g.state.parser:get_id() end
function fb.get_current_parser_keyname() return g.state.parser.keybind_name or g.state.parser.name end
function fb.get_selected_index() return g.state.selected end
function fb.get_selected_item() return fb.copy_table(g.state.list[g.state.selected]) end
function fb.get_open_status() return not g.state.hidden end
function fb.get_parse_state(co) return g.parse_states[co or coroutine.running() or ""] end
function fb.set_empty_text(str)
g.state.empty_text = str
fb.redraw()
end
function fb.set_selected_index(index)
if type(index) ~= "number" then return false end
if index < 1 then index = 1 end
if index > #g.state.list then index = #g.state.list end
g.state.selected = index
fb.redraw()
return index
end
return fb

View File

@@ -1,32 +0,0 @@
local msg = require 'mp.msg'
local g = require 'modules.globals'
local parse_state_API = {}
--a wrapper around coroutine.yield that aborts the coroutine if
--the parse request was cancelled by the user
--the coroutine is
function parse_state_API:yield(...)
local co = coroutine.running()
local is_browser = co == g.state.co
if self.source == "browser" and not is_browser then
msg.error("current coroutine does not match browser's expected coroutine - did you unsafely yield before this?")
error("current coroutine does not match browser's expected coroutine - aborting the parse")
end
local result = table.pack(coroutine.yield(...))
if is_browser and co ~= g.state.co then
msg.verbose("browser no longer waiting for list - aborting parse for", self.directory)
error(g.ABORT_ERROR)
end
return unpack(result, 1, result.n)
end
--checks if the current coroutine is the one handling the browser's request
function parse_state_API:is_coroutine_current()
return coroutine.running() == g.state.co
end
return parse_state_API

View File

@@ -1,25 +0,0 @@
local msg = require 'mp.msg'
local g = require 'modules.globals'
local scanning = require 'modules.navigation.scanning'
local fb = require 'modules.apis.fb'
local parser_api = setmetatable({}, { __index = fb })
function parser_api:get_index() return g.parsers[self].index end
function parser_api:get_id() return g.parsers[self].id end
--a wrapper that passes the parsers priority value if none other is specified
function parser_api:register_root_item(item, priority)
return fb.register_root_item(item, priority or g.parsers[self:get_id()].priority)
end
--runs choose_and_parse starting from the next parser
function parser_api:defer(directory)
msg.trace("deferring to other parsers...")
local list, opts = scanning.choose_and_parse(directory, self:get_index() + 1)
fb.get_parse_state().already_deferred = true
return list, opts
end
return parser_api

View File

@@ -1,175 +0,0 @@
--------------------------------------------------------------------------------------------------------
-----------------------------------------List Formatting------------------------------------------------
--------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------
local utils = require 'mp.utils'
local g = require 'modules.globals'
local o = require 'modules.options'
local fb_utils = require 'modules.utils'
local state = g.state
local style = g.style
local ass = g.ass
local function draw()
ass:update()
end
local function remove()
ass:remove()
end
local string_buffer = {}
--appends the entered text to the overlay
local function append(...)
for i = 1, select("#", ...) do
table.insert(string_buffer, select(i, ...) or '' )
end
end
--appends a newline character to the osd
local function newline()
table.insert(string_buffer, '\\N')
end
local function flush_buffer()
ass.data = table.concat(string_buffer, '')
string_buffer = {}
end
--detects whether or not to highlight the given entry as being played
local function highlight_entry(v)
if g.current_file.path == nil then return false end
local full_path = fb_utils.get_full_path(v)
local alt_path = v.name and g.state.directory..v.name or nil
if fb_utils.parseable_item(v) then
return string.find(g.current_file.directory, full_path, 1, true)
or (alt_path and string.find(g.current_file.directory, alt_path, 1, true))
else
return g.current_file.path == full_path
or (alt_path and g.current_file.path == alt_path)
end
end
local ass_cache = setmetatable({}, {__mode = 'k'})
-- escape ass values and replace newlines
local function ass_escape(str)
if ass_cache[str] then return ass_cache[str] end
local escaped = fb_utils.ass_escape(str, true)
ass_cache[str] = escaped
return escaped
end
--refreshes the ass text using the contents of the list
local function update_ass()
if state.hidden then state.flag_update = true ; return end
append(style.global)
local dir_name = state.directory_label or state.directory
if dir_name == "" then dir_name = "ROOT" end
append(style.header)
append(fb_utils.substitute_codes(o.format_string_header, nil, nil, nil, ass_escape))
newline()
if #state.list < 1 then
append(state.empty_text)
flush_buffer()
draw()
return
end
local start = 1
local finish = start+o.num_entries-1
--handling cursor positioning
local mid = math.ceil(o.num_entries/2)+1
if state.selected+mid > finish then
local offset = state.selected - finish + mid
--if we've overshot the end of the list then undo some of the offset
if finish + offset > #state.list then
offset = offset - ((finish+offset) - #state.list)
end
start = start + offset
finish = finish + offset
end
--making sure that we don't overstep the boundaries
if start < 1 then start = 1 end
local overflow = finish < #state.list
--this is necessary when the number of items in the dir is less than the max
if not overflow then finish = #state.list end
-- these are the number values to place into the wrappers
local wrapper_overrides = {['<'] = tostring(start-1), ['>'] = tostring(#state.list-finish)}
--adding a header to show there are items above in the list
if o.format_string_topwrapper ~= '' and start > 1 then
append(style.footer_header, fb_utils.substitute_codes(o.format_string_topwrapper, wrapper_overrides, nil, nil, ass_escape))
newline()
end
for i=start, finish do
local v = state.list[i]
local playing_file = highlight_entry(v)
append(style.body)
--handles custom styles for different entries
if i == state.selected or i == state.multiselect_start then
if not (i == state.selected) then append(style.selection_marker) end
if not state.multiselect_start then append(style.cursor)
else
if state.selection[state.multiselect_start] then append(style.cursor_select)
else append(style.cursor_deselect) end
end
append(o.cursor_icon, "\\h", style.body)
else
append(g.style.indent, o.cursor_icon, "\\h", style.body)
end
--sets the selection colour scheme
local multiselected = state.selection[i]
--sets the colour for the item
local function set_colour()
if multiselected then append(style.multiselect)
elseif i == state.selected then append(style.selected) end
if playing_file then append( multiselected and style.playing_selected or style.playing) end
end
set_colour()
--sets the folder icon
if v.type == 'dir' then
append(style.folder, o.folder_icon, "\\h", style.body)
set_colour()
end
--adds the actual name of the item
append(v.ass or ass_escape(v.label or v.name))
newline()
end
if o.format_string_bottomwrapper ~= '' and overflow then
append(style.footer_header)
append(fb_utils.substitute_codes(o.format_string_bottomwrapper, wrapper_overrides, nil, nil, ass_escape))
end
flush_buffer()
draw()
end
return {
update_ass = update_ass,
highlight_entry = highlight_entry,
draw = draw,
remove = remove,
}

View File

@@ -1,139 +0,0 @@
--------------------------------------------------------------------------------------------------------
--------------------------------------Cache Implementation----------------------------------------------
--------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------
local msg = require 'mp.msg'
local utils = require 'mp.utils'
local g = require 'modules.globals'
local fb_utils = require 'modules.utils'
local function get_keys(t)
local keys = {}
for key in pairs(t) do
table.insert(keys, key)
end
return keys
end
local cache = {
cache = setmetatable({}, {__mode = 'kv'}),
traversal_stack = {},
history = {},
cached_values = {
"directory", "directory_label", "list", "selected", "selection", "parser", "empty_text", "co"
},
dangling_refs = {},
}
function cache:print_debug_info()
local cache_keys = get_keys(self.cache)
msg.verbose('Printing cache debug info')
msg.verbose('cache size:', #cache_keys)
msg.debug(utils.to_string(cache_keys))
msg.trace(utils.to_string(self.cache[cache_keys[#cache_keys]]))
msg.verbose('traversal_stack size:', #self.traversal_stack)
msg.debug(utils.to_string(fb_utils.list.map(self.traversal_stack, function(ref) return ref.directory end)))
msg.verbose('history size:', #self.history)
msg.debug(utils.to_string(fb_utils.list.map(self.history, function(ref) return ref.directory end)))
end
function cache:replace_dangling_refs(directory, ref)
for _, v in ipairs(self.traversal_stack) do
if v.directory == directory then
v.ref = ref
self.dangling_refs[directory] = nil
end
end
for _, v in ipairs(self.history) do
if v.directory == directory then
v.ref = ref
self.dangling_refs[directory] = nil
end
end
end
function cache:add_current_state()
local directory = g.state.directory
if directory == nil then return end
local t = self.cache[directory] or {}
for _, value in ipairs(self.cached_values) do
t[value] = g.state[value]
end
self.cache[directory] = t
if self.dangling_refs[directory] then
self:replace_dangling_refs(directory, t)
end
end
-- Creates a reference to the cache of a particular directory to prevent it
-- from being garbage collected.
function cache:get_cache_ref(directory)
return {
directory = directory,
ref = self.cache[directory],
}
end
function cache:append_history()
self:add_current_state()
local history_size = #self.history
-- We don't want to have the same directory in the history over and over again.
if history_size > 0 and self.history[history_size].directory == g.state.directory then return end
table.insert(self.history, self:get_cache_ref(g.state.directory))
if (history_size + 1) > 100 then table.remove(self.history, 1) end
end
function cache:in_cache(directory)
return self.cache[directory] ~= nil
end
function cache:apply(directory)
directory = directory or g.state.directory
local t = self.cache[directory]
if not t then return false end
msg.verbose('applying cache for', directory)
for _, value in ipairs(self.cached_values) do
msg.debug('setting', value, 'to', t[value])
g.state[value] = t[value]
end
return true
end
function cache:push()
local stack_size = #self.traversal_stack
if stack_size > 0 and self.traversal_stack[stack_size].directory == g.state.directory then return end
table.insert(self.traversal_stack, self:get_cache_ref(g.state.directory))
end
function cache:pop()
table.remove(self.traversal_stack)
end
function cache:clear_traversal_stack()
self.traversal_stack = {}
end
function cache:clear()
self.cache = setmetatable({}, {__mode = 'kv'})
for _, v in ipairs(self.traversal_stack) do
v.ref = nil
self.dangling_refs[v.directory] = true
end
for _, v in ipairs(self.history) do
v.ref = nil
self.dangling_refs[v.directory] = true
end
end
return cache

View File

@@ -1,90 +0,0 @@
local mp = require 'mp'
local msg = require 'mp.msg'
local utils = require 'mp.utils'
local o = require 'modules.options'
local g = require 'modules.globals'
local fb_utils = require 'modules.utils'
local movement = require 'modules.navigation.directory-movement'
local ass = require 'modules.ass'
local cursor = require 'modules.navigation.cursor'
local controls = {}
--opens the browser
function controls.open()
if not g.state.hidden then return end
for _,v in ipairs(g.state.keybinds) do
mp.add_forced_key_binding(v[1], 'dynamic/'..v[2], v[3], v[4])
end
if o.set_shared_script_properties then utils.shared_script_property_set('file_browser-open', 'yes') end
if o.set_user_data then mp.set_property_bool('user-data/file_browser/open', true) end
if o.toggle_idlescreen then mp.commandv('script-message', 'osc-idlescreen', 'no', 'no_osd') end
g.state.hidden = false
if g.state.directory == nil then
local path = mp.get_property('path')
if path or o.default_to_working_directory then movement.goto_current_dir() else movement.goto_root() end
return
end
if not g.state.flag_update then ass.draw()
else g.state.flag_update = false ; ass.update_ass() end
end
--closes the list and sets the hidden flag
function controls.close()
if g.state.hidden then return end
for _,v in ipairs(g.state.keybinds) do
mp.remove_key_binding('dynamic/'..v[2])
end
if o.set_shared_script_properties then utils.shared_script_property_set("file_browser-open", "no") end
if o.set_user_data then mp.set_property_bool('user-data/file_browser/open', false) end
if o.toggle_idlescreen then mp.commandv('script-message', 'osc-idlescreen', 'yes', 'no_osd') end
g.state.hidden = true
ass.remove()
end
--toggles the list
function controls.toggle()
if g.state.hidden then controls.open()
else controls.close() end
end
--run when the escape key is used
function controls.escape()
--if multiple items are selection cancel the
--selection instead of closing the browser
if next(g.state.selection) or g.state.multiselect_start then
g.state.selection = {}
cursor.disable_select_mode()
ass.update_ass()
return
end
controls.close()
end
--opens a specific directory
function controls.browse_directory(directory, open_browser)
if not directory then return end
if open_browser == nil then open_browser = true end
directory = mp.command_native({"expand-path", directory}) or ''
-- directory = join_path( mp.get_property("working-directory", ""), directory )
if directory ~= "" then directory = fb_utils.fix_path(directory, true) end
msg.verbose('recieved directory from script message: '..directory)
directory = fb_utils.resolve_directory_mapping(directory)
local co = movement.goto_directory(directory)
if open_browser then controls.open() end
return co
end
return controls

View File

@@ -1,115 +0,0 @@
--------------------------------------------------------------------------------------------------------
------------------------------------------Variable Setup------------------------------------------------
--------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------
local mp = require 'mp'
local globals = {}
local o = require 'modules.options'
--sets the version for the file-browser API
globals.API_VERSION = "1.7.0"
--gets the current platform (only works in mpv v0.36+)
globals.PLATFORM = mp.get_property_native('platform')
--the osd_overlay API was not added until v0.31. The expand-path command was not added until 0.30
assert(mp.create_osd_overlay, "Script requires minimum mpv version 0.33")
globals.ass = mp.create_osd_overlay("ass-events")
globals.ass.res_y = 720 / o.scaling_factor_base
local BASE_FONT_SIZE = 25
globals.style = {
global = o.alignment == 0 and "" or ([[{\an%d}]]):format(o.alignment),
-- full line styles
header = ([[{\r\q2\b%s\fs%d\fn%s\c&H%s&}]]):format((o.font_bold_header and "1" or "0"), o.scaling_factor_header*BASE_FONT_SIZE, o.font_name_header, o.font_colour_header),
body = ([[{\r\q2\fs%d\fn%s\c&H%s&}]]):format(BASE_FONT_SIZE, o.font_name_body, o.font_colour_body),
footer_header = ([[{\r\q2\fs%d\fn%s\c&H%s&}]]):format(o.scaling_factor_wrappers*BASE_FONT_SIZE, o.font_name_wrappers, o.font_colour_wrappers),
--small section styles (for colours)
multiselect = ([[{\c&H%s&}]]):format(o.font_colour_multiselect),
selected = ([[{\c&H%s&}]]):format(o.font_colour_selected),
playing = ([[{\c&H%s&}]]):format(o.font_colour_playing),
playing_selected = ([[{\c&H%s&}]]):format(o.font_colour_playing_multiselected),
--icon styles
indent = ([[{\alpha&H%s}]]):format('ff'),
cursor = ([[{\fn%s\c&H%s&}]]):format(o.font_name_cursor, o.font_colour_cursor),
cursor_select = ([[{\fn%s\c&H%s&}]]):format(o.font_name_cursor, o.font_colour_multiselect),
cursor_deselect = ([[{\fn%s\c&H%s&}]]):format(o.font_name_cursor, o.font_colour_selected),
folder = ([[{\fn%s}]]):format(o.font_name_folder),
selection_marker = ([[{\alpha&H%s}]]):format(o.font_opacity_selection_marker),
}
globals.state = {
list = {},
selected = 1,
hidden = true,
flag_update = false,
keybinds = nil,
parser = nil,
directory = nil,
directory_label = nil,
prev_directory = "",
co = nil,
multiselect_start = nil,
initial_selection = nil,
selection = {}
}
--the parser table actually contains 3 entries for each parser
--a numeric entry which represents the priority of the parsers and has the parser object as the value
--a string entry representing the id of each parser and with the parser object as the value
--and a table entry with the parser itself as the key and a table value in the form { id = %s, index = %d }
globals.parsers = {}
--this table contains the parse_state tables for every parse operation indexed with the coroutine used for the parse
--this table has weakly referenced keys, meaning that once the coroutine for a parse is no-longer used by anything that
--field in the table will be removed by the garbage collector
globals.parse_states = setmetatable({}, { __mode = "k"})
globals.extensions = {}
globals.sub_extensions = {}
globals.audio_extensions = {}
globals.parseable_extensions = {}
--This table contains mappings to convert external directories to cannonical
--locations within the file-browser file tree. The keys of the table are Lua
--patterns used to evaluate external directory paths. The value is the path
--that should replace the part of the path than matched the pattern.
--These mappings should only applied at the edges where external paths are
--ingested by file-browser.
globals.directory_mappings = {}
globals.current_file = {
directory = nil,
name = nil,
path = nil,
original_path = nil,
}
globals.root = {}
--default list of compatible file extensions
--adding an item to this list is a valid request on github
globals.compatible_file_extensions = {
"264","265","3g2","3ga","3ga2","3gp","3gp2","3gpp","3iv","a52","aac","adt","adts","ahn","aif","aifc","aiff","amr","ape","asf","au","avc","avi","awb","ay",
"bmp","cue","divx","dts","dtshd","dts-hd","dv","dvr","dvr-ms","eac3","evo","evob","f4a","flac","flc","fli","flic","flv","gbs","gif","gxf","gym",
"h264","h265","hdmov","hdv","hes","hevc","jpeg","jpg","kss","lpcm","m1a","m1v","m2a","m2t","m2ts","m2v","m3u","m3u8","m4a","m4v","mk3d","mka","mkv",
"mlp","mod","mov","mp1","mp2","mp2v","mp3","mp4","mp4v","mp4v","mpa","mpe","mpeg","mpeg2","mpeg4","mpg","mpg4","mpv","mpv2","mts","mtv","mxf","nsf",
"nsfe","nsv","nut","oga","ogg","ogm","ogv","ogx","opus","pcm","pls","png","qt","ra","ram","rm","rmvb","sap","snd","spc","spx","svg","thd","thd+ac3",
"tif","tiff","tod","trp","truehd","true-hd","ts","tsa","tsv","tta","tts","vfw","vgm","vgz","vob","vro","wav","weba","webm","webp","wm","wma","wmv","wtv",
"wv","x264","x265","xvid","y4m","yuv"
}
globals.ABORT_ERROR = {
msg = "browser is no longer waiting for list - aborting parse"
}
return globals

View File

@@ -1,308 +0,0 @@
------------------------------------------------------------------------------------------
----------------------------------Keybind Implementation----------------------------------
------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------
local mp = require 'mp'
local msg = require 'mp.msg'
local utils = require 'mp.utils'
local o = require 'modules.options'
local g = require 'modules.globals'
local fb_utils = require 'modules.utils'
local addons = require 'modules.addons'
local playlist = require 'modules.playlist'
local controls = require 'modules.controls'
local movement = require 'modules.navigation.directory-movement'
local scanning = require 'modules.navigation.scanning'
local cursor = require 'modules.navigation.cursor'
local cache = require 'modules.cache'
g.state.keybinds = {
{'ENTER', 'play', function() playlist.add_files('replace', false) end},
{'Shift+ENTER', 'play_append', function() playlist.add_files('append-play', false) end},
{'Alt+ENTER', 'play_autoload',function() playlist.add_files('replace', true) end},
{'ESC', 'close', controls.escape},
{'RIGHT', 'down_dir', movement.down_dir},
{'LEFT', 'up_dir', movement.up_dir},
{'DOWN', 'scroll_down', function() cursor.scroll(1, o.wrap) end, {repeatable = true}},
{'UP', 'scroll_up', function() cursor.scroll(-1, o.wrap) end, {repeatable = true}},
{'PGDWN', 'page_down', function() cursor.scroll(o.num_entries) end, {repeatable = true}},
{'PGUP', 'page_up', function() cursor.scroll(-o.num_entries) end, {repeatable = true}},
{'Shift+PGDWN', 'list_bottom', function() cursor.scroll(math.huge) end},
{'Shift+PGUP', 'list_top', function() cursor.scroll(-math.huge) end},
{'HOME', 'goto_current', movement.goto_current_dir},
{'Shift+HOME', 'goto_root', movement.goto_root},
{'Ctrl+r', 'reload', function() cache:clear(); scanning.rescan() end},
{'s', 'select_mode', cursor.toggle_select_mode},
{'S', 'select_item', cursor.toggle_selection},
{'Ctrl+a', 'select_all', cursor.select_all}
}
--a map of key-keybinds - only saves the latest keybind if multiple have the same key code
local top_level_keys = {}
--format the item string for either single or multiple items
local function create_item_string(base_code_fn, items, state, cmd, quoted)
if not items[1] then return end
local func = quoted and function(...) return ("%q"):format(base_code_fn(...)) end or base_code_fn
local out = {}
for _, item in ipairs(items) do
table.insert(out, func(item, state))
end
return table.concat(out, cmd['concat-string'] or ' ')
end
local KEYBIND_CODE_PATTERN = fb_utils.get_code_pattern(fb_utils.code_fns)
local item_specific_codes = 'fnij'
--substitutes the key codes for the
local function substitute_codes(str, cmd, items, state)
local overrides = {}
for code in item_specific_codes:gmatch('.') do
overrides[code] = function(_,s) return create_item_string(fb_utils.code_fns[code], items, s, cmd) end
overrides[code:upper()] = function(_,s) return create_item_string(fb_utils.code_fns[code], items, s, cmd, true) end
end
return fb_utils.substitute_codes(str, overrides, items[1], state)
end
--iterates through the command table and substitutes special
--character codes for the correct strings used for custom functions
local function format_command_table(cmd, items, state)
local copy = {}
for i = 1, #cmd.command do
copy[i] = {}
for j = 1, #cmd.command[i] do
copy[i][j] = substitute_codes(cmd.command[i][j], cmd, items, state)
end
end
return copy
end
--runs all of the commands in the command table
--key.command must be an array of command tables compatible with mp.command_native
--items must be an array of multiple items (when multi-type ~= concat the array will be 1 long)
local function run_custom_command(cmd, items, state)
local custom_cmds = cmd.codes and format_command_table(cmd, items, state) or cmd.command
for _, custom_cmd in ipairs(custom_cmds) do
msg.debug("running command:", utils.to_string(custom_cmd))
mp.command_native(custom_cmd)
end
end
--returns true if the given code set has item specific codes (%f, %i, etc)
local function has_item_codes(codes)
for code in pairs(codes) do
if item_specific_codes:find(code:lower(), 1, true) then return true end
end
return false
end
--runs one of the custom commands
local function run_custom_keybind(cmd, state, co)
--evaluates a condition and passes through the correct values
local function evaluate_condition(condition, items)
local cond = substitute_codes(condition, cmd, items, state)
return fb_utils.evaluate_string('return '..cond) == true
end
-- evaluates the string condition to decide if the keybind should be run
local do_item_condition
if cmd.condition then
if has_item_codes(cmd.condition_codes) then
do_item_condition = true
elseif not evaluate_condition(cmd.condition, {}) then
return false
end
end
if cmd.parser then
local parser_str = ' '..cmd.parser..' '
if not parser_str:find( '%W'..(state.parser.keybind_name or state.parser.name)..'%W' ) then return false end
end
--these are for the default keybinds, or from addons which use direct functions
if type(cmd.command) == 'function' then return cmd.command(cmd, cmd.addon and fb_utils.copy_table(state) or state, co) end
--the function terminates here if we are running the command on a single item
if not (cmd.multiselect and next(state.selection)) then
if cmd.filter then
if not state.list[state.selected] then return false end
if state.list[state.selected].type ~= cmd.filter then return false end
end
if cmd.codes then
--if the directory is empty, and this command needs to work on an item, then abort and fallback to the next command
if not state.list[state.selected] and has_item_codes(cmd.codes) then return false end
end
if do_item_condition and not evaluate_condition(cmd.condition, { state.list[state.selected] }) then
return false
end
run_custom_command(cmd, { state.list[state.selected] }, state)
return true
end
--runs the command on all multi-selected items
local selection = fb_utils.sort_keys(state.selection, function(item)
if do_item_condition and not evaluate_condition(cmd.condition, { item }) then return false end
return not cmd.filter or item.type == cmd.filter
end)
if not next(selection) then return false end
if cmd["multi-type"] == "concat" then
run_custom_command(cmd, selection, state)
elseif cmd["multi-type"] == "repeat" or cmd["multi-type"] == nil then
for i,_ in ipairs(selection) do
run_custom_command(cmd, {selection[i]}, state)
if cmd.delay then
mp.add_timeout(cmd.delay, function() fb_utils.coroutine.resume_err(co) end)
coroutine.yield()
end
end
end
--we passthrough by default if the command is not run on every selected item
if cmd.passthrough ~= nil then return end
local num_selection = 0
for _ in pairs(state.selection) do num_selection = num_selection+1 end
return #selection == num_selection
end
--recursively runs the keybind functions, passing down through the chain
--of keybinds with the same key value
local function run_keybind_recursive(keybind, state, co)
msg.trace("Attempting custom command:", utils.to_string(keybind))
if keybind.passthrough ~= nil then
run_custom_keybind(keybind, state, co)
if keybind.passthrough == true and keybind.prev_key then
run_keybind_recursive(keybind.prev_key, state, co)
end
else
if run_custom_keybind(keybind, state, co) == false and keybind.prev_key then
run_keybind_recursive(keybind.prev_key, state, co)
end
end
end
--a wrapper to run a custom keybind as a lua coroutine
local function run_keybind_coroutine(key)
msg.debug("Received custom keybind "..key.key)
local co = coroutine.create(run_keybind_recursive)
local state_copy = {
directory = g.state.directory,
directory_label = g.state.directory_label,
list = g.state.list, --the list should remain unchanged once it has been saved to the global state, new directories get new tables
selected = g.state.selected,
selection = fb_utils.copy_table(g.state.selection),
parser = g.state.parser,
}
local success, err = coroutine.resume(co, key, state_copy, co)
if not success then
msg.error("error running keybind:", utils.to_string(key))
fb_utils.traceback(err, co)
end
end
--scans the given command table to identify if they contain any custom keybind codes
local function scan_for_codes(command_table, codes)
if type(command_table) ~= "table" then return codes end
for _, value in pairs(command_table) do
local type = type(value)
if type == "table" then
scan_for_codes(value, codes)
elseif type == "string" then
for code in value:gmatch(KEYBIND_CODE_PATTERN) do
codes[code] = true
end
end
end
return codes
end
--inserting the custom keybind into the keybind array for declaration when file-browser is opened
--custom keybinds with matching names will overwrite eachother
local function insert_custom_keybind(keybind)
-- api checking for the keybinds is optional, so set to a valid version if it does not exist
keybind.api_version = keybind.api_version or '1.0.0'
if not addons.check_api_version(keybind, 'keybind '..keybind.name) then return end
--we'll always save the keybinds as either an array of command arrays or a function
if type(keybind.command) == "table" and type(keybind.command[1]) ~= "table" then
keybind.command = {keybind.command}
end
keybind.codes = scan_for_codes(keybind.command, {})
if not next(keybind.codes) then keybind.codes = nil end
keybind.prev_key = top_level_keys[keybind.key]
if keybind.condition then
keybind.condition_codes = {}
for code in string.gmatch(keybind.condition, KEYBIND_CODE_PATTERN) do keybind.condition_codes[code] = true end
end
table.insert(g.state.keybinds, {keybind.key, keybind.name, function() run_keybind_coroutine(keybind) end, keybind.flags or {}})
top_level_keys[keybind.key] = keybind
end
--loading the custom keybinds
--can either load keybinds from the config file, from addons, or from both
local function setup_keybinds()
if not o.custom_keybinds and not o.addons then return end
--this is to make the default keybinds compatible with passthrough from custom keybinds
for _, keybind in ipairs(g.state.keybinds) do
top_level_keys[keybind[1]] = { key = keybind[1], name = keybind[2], command = keybind[3], flags = keybind[4] }
end
--this loads keybinds from addons
if o.addons then
for i = #g.parsers, 1, -1 do
local parser = g.parsers[i]
if parser.keybinds then
for i, keybind in ipairs(parser.keybinds) do
--if addons use the native array command format, then we need to convert them over to the custom command format
if not keybind.key then keybind = { key = keybind[1], name = keybind[2], command = keybind[3], flags = keybind[4] }
else keybind = fb_utils.copy_table(keybind) end
keybind.name = g.parsers[parser].id.."/"..(keybind.name or tostring(i))
keybind.addon = true
insert_custom_keybind(keybind)
end
end
end
end
--loads custom keybinds from file-browser-keybinds.json
if o.custom_keybinds then
local path = mp.command_native({"expand-path", "~~/script-opts"}).."/file-browser-keybinds.json"
local custom_keybinds, err = io.open( path )
if not custom_keybinds then return error(err) end
local json = custom_keybinds:read("*a")
custom_keybinds:close()
json = utils.parse_json(json)
if not json then return error("invalid json syntax for "..path) end
for i, keybind in ipairs(json) do
keybind.name = "custom/"..(keybind.name or tostring(i))
insert_custom_keybind(keybind)
end
end
end
return {
setup_keybinds = setup_keybinds,
}

View File

@@ -1,121 +0,0 @@
--------------------------------------------------------------------------------------------------------
--------------------------------Scroll/Select Implementation--------------------------------------------
--------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------
local g = require 'modules.globals'
local fb_utils = require 'modules.utils'
local ass = require 'modules.ass'
local cursor = {}
--disables multiselect
function cursor.disable_select_mode()
g.state.multiselect_start = nil
g.state.initial_selection = nil
end
--enables multiselect
function cursor.enable_select_mode()
g.state.multiselect_start = g.state.selected
g.state.initial_selection = fb_utils.copy_table(g.state.selection)
end
--calculates what drag behaviour is required for that specific movement
local function drag_select(original_pos, new_pos)
if original_pos == new_pos then return end
local setting = g.state.selection[g.state.multiselect_start]
for i = original_pos, new_pos, (new_pos > original_pos and 1 or -1) do
--if we're moving the cursor away from the starting point then set the selection
--otherwise restore the original selection
if i > g.state.multiselect_start then
if new_pos > original_pos then
g.state.selection[i] = setting
elseif i ~= new_pos then
g.state.selection[i] = g.state.initial_selection[i]
end
elseif i < g.state.multiselect_start then
if new_pos < original_pos then
g.state.selection[i] = setting
elseif i ~= new_pos then
g.state.selection[i] = g.state.initial_selection[i]
end
end
end
end
--moves the selector up and down the list by the entered amount
function cursor.scroll(n, wrap)
local num_items = #g.state.list
if num_items == 0 then return end
local original_pos = g.state.selected
if original_pos + n > num_items then
g.state.selected = wrap and 1 or num_items
elseif original_pos + n < 1 then
g.state.selected = wrap and num_items or 1
else
g.state.selected = original_pos + n
end
if g.state.multiselect_start then drag_select(original_pos, g.state.selected) end
ass.update_ass()
end
--selects the first item in the list which is highlighted as playing
function cursor.select_playing_item()
for i,item in ipairs(g.state.list) do
if ass.highlight_entry(item) then
g.state.selected = i
return
end
end
end
--scans the list for which item to select by default
--chooses the folder that the script just moved out of
--or, otherwise, the item highlighted as currently playing
function cursor.select_prev_directory()
if g.state.prev_directory:find(g.state.directory, 1, true) == 1 then
local i = 1
while (g.state.list[i] and fb_utils.parseable_item(g.state.list[i])) do
if g.state.prev_directory:find(fb_utils.get_full_path(g.state.list[i]), 1, true) then
g.state.selected = i
return
end
i = i+1
end
end
cursor.select_playing_item()
end
--toggles the selection
function cursor.toggle_selection()
if not g.state.list[g.state.selected] then return end
g.state.selection[g.state.selected] = not g.state.selection[g.state.selected] or nil
ass.update_ass()
end
--select all items in the list
function cursor.select_all()
for i,_ in ipairs(g.state.list) do
g.state.selection[i] = true
end
ass.update_ass()
end
--toggles select mode
function cursor.toggle_select_mode()
if g.state.multiselect_start == nil then
cursor.enable_select_mode()
cursor.toggle_selection()
else
cursor.disable_select_mode()
ass.update_ass()
end
end
return cursor

View File

@@ -1,86 +0,0 @@
local mp = require 'mp'
local msg = require 'mp.msg'
local utils = require 'mp.utils'
local o = require 'modules.options'
local g = require 'modules.globals'
local ass = require 'modules.ass'
local cache = require 'modules.cache'
local scanning = require 'modules.navigation.scanning'
local fb_utils = require 'modules.utils'
local directory_movement = {}
function directory_movement.set_current_file(filepath)
--if we're in idle mode then we want to open the working directory
if filepath == nil then
g.current_file.directory = fb_utils.fix_path( mp.get_property("working-directory", ""), true)
g.current_file.name = nil
g.current_file.path = nil
return
end
local absolute_path = fb_utils.absolute_path(filepath)
local resolved_path = fb_utils.resolve_directory_mapping(absolute_path)
g.current_file.directory, g.current_file.name = utils.split_path(resolved_path)
g.current_file.original_path = absolute_path
g.current_file.path = resolved_path
if not g.state.hidden then ass.update_ass()
else g.state.flag_update = true end
end
--the base function for moving to a directory
function directory_movement.goto_directory(directory, moving_adjacent)
-- update cache to the lastest state values before changing the current directory
cache:add_current_state()
local current = g.state.list[g.state.selected]
g.state.directory = directory
if g.state.directory_label then
if moving_adjacent == 1 then
g.state.directory_label = g.state.directory_label..(current.label or current.name)
elseif moving_adjacent == -1 then
g.state.directory_label = string.match(g.state.directory_label, "^(.-/+)[^/]+/*$")
end
end
return scanning.rescan(moving_adjacent or false)
end
--loads the root list
function directory_movement.goto_root()
msg.verbose('jumping to root')
return directory_movement.goto_directory("")
end
--switches to the directory of the currently playing file
function directory_movement.goto_current_dir()
msg.verbose('jumping to current directory')
return directory_movement.goto_directory(g.current_file.directory)
end
--moves up a directory
function directory_movement.up_dir()
local parent_dir = g.state.directory:match("^(.-/+)[^/]+/*$") or ""
if o.skip_protocol_schemes and parent_dir:find("^(%a[%w+-.]*)://$") then
return directory_movement.goto_root()
end
return directory_movement.goto_directory(parent_dir, -1)
end
--moves down a directory
function directory_movement.down_dir()
local current = g.state.list[g.state.selected]
if not current or not fb_utils.parseable_item(current) then return end
local directory, redirected = fb_utils.get_new_directory(current, g.state.directory)
return directory_movement.goto_directory(directory, not redirected and 1)
end
return directory_movement

View File

@@ -1,182 +0,0 @@
local mp = require 'mp'
local msg = require 'mp.msg'
local utils = require 'mp.utils'
local g = require 'modules.globals'
local fb_utils = require 'modules.utils'
local cache = require 'modules.cache'
local cursor = require 'modules.navigation.cursor'
local ass = require 'modules.ass'
local parse_state_API = require 'modules.apis.parse-state'
local function clear_non_adjacent_state()
g.state.directory_label = nil
cache:clear_traversal_stack()
end
--parses the given directory or defers to the next parser if nil is returned
local function choose_and_parse(directory, index)
msg.debug(("finding parser for %q"):format(directory))
local parser, list, opts
local parse_state = g.parse_states[coroutine.running() or ""]
while list == nil and not parse_state.already_deferred and index <= #g.parsers do
parser = g.parsers[index]
if parser:can_parse(directory, parse_state) then
msg.debug("attempting parser:", parser:get_id())
list, opts = parser:parse(directory, parse_state)
end
index = index + 1
end
if not list then return nil, {} end
msg.debug("list returned from:", parser:get_id())
opts = opts or {}
if list then opts.id = opts.id or parser:get_id() end
return list, opts
end
--sets up the parse_state table and runs the parse operation
local function run_parse(directory, parse_state)
msg.verbose(("scanning files in %q"):format(directory))
parse_state.directory = directory
local co = coroutine.running()
g.parse_states[co] = setmetatable(parse_state, { __index = parse_state_API })
local list, opts = choose_and_parse(directory, 1)
if list == nil then return msg.debug("no successful parsers found") end
opts.parser = g.parsers[opts.id]
if not opts.filtered then fb_utils.filter(list) end
if not opts.sorted then fb_utils.sort(list) end
return list, opts
end
--returns the contents of the given directory using the given parse state
--if a coroutine has already been used for a parse then create a new coroutine so that
--the every parse operation has a unique thread ID
local function parse_directory(directory, parse_state)
local co = fb_utils.coroutine.assert("scan_directory must be executed from within a coroutine - aborting scan "..utils.to_string(parse_state))
if not g.parse_states[co] then return run_parse(directory, parse_state) end
--if this coroutine is already is use by another parse operation then we create a new
--one and hand execution over to that
local new_co = coroutine.create(function()
fb_utils.coroutine.resume_err(co, run_parse(directory, parse_state))
end)
--queue the new coroutine on the mpv event queue
mp.add_timeout(0, function()
local success, err = coroutine.resume(new_co)
if not success then
fb_utils.traceback(err, new_co)
fb_utils.coroutine.resume_err(co)
end
end)
return g.parse_states[co]:yield()
end
--sends update requests to the different parsers
local function update_list(moving_adjacent)
msg.verbose('opening directory: ' .. g.state.directory)
g.state.selected = 1
g.state.selection = {}
--loads the current directry from the cache to save loading time
if cache:in_cache(g.state.directory) then
msg.verbose('found directory in cache')
cache:apply(g.state.directory)
g.state.prev_directory = g.state.directory
return
end
local directory = g.state.directory
local list, opts = parse_directory(g.state.directory, { source = "browser" })
--if the running coroutine isn't the one stored in the state variable, then the user
--changed directories while the coroutine was paused, and this operation should be aborted
if coroutine.running() ~= g.state.co then
msg.verbose(g.ABORT_ERROR.msg)
msg.debug("expected:", g.state.directory, "received:", directory)
return
end
--apply fallbacks if the scan failed
if not list and cache:in_cache(g.state.prev_directory) then
--switches settings back to the previously opened directory
--to the user it will be like the directory never changed
msg.warn("could not read directory", g.state.directory)
cache:apply(g.state.prev_directory)
return
elseif not list then
--opens the root instead
msg.warn("could not read directory", g.state.directory, "redirecting to root")
list, opts = parse_directory("", { source = "browser" })
-- sets the directory redirect flag
opts.directory = ''
end
g.state.list = list
g.state.parser = opts.parser
--setting custom options from parsers
g.state.directory_label = opts.directory_label
g.state.empty_text = opts.empty_text or g.state.empty_text
--we assume that directory is only changed when redirecting to a different location
--therefore we need to change the `moving_adjacent` flag and clear some state values
if opts.directory then
g.state.directory = opts.directory
moving_adjacent = false
clear_non_adjacent_state()
end
if opts.selected_index then
g.state.selected = opts.selected_index or g.state.selected
if g.state.selected > #g.state.list then g.state.selected = #g.state.list
elseif g.state.selected < 1 then g.state.selected = 1 end
end
if moving_adjacent then cursor.select_prev_directory()
else cursor.select_playing_item() end
g.state.prev_directory = g.state.directory
end
--rescans the folder and updates the list
--returns the coroutine for the new parse operation
local function rescan(moving_adjacent)
if moving_adjacent == nil then moving_adjacent = 0 end
--we can only make assumptions about the directory label when moving from adjacent directories
if not moving_adjacent then clear_non_adjacent_state() end
g.state.empty_text = "~"
g.state.list = {}
cursor.disable_select_mode()
ass.update_ass()
--the directory is always handled within a coroutine to allow addons to
--pause execution for asynchronous operations
g.state.co = fb_utils.coroutine.queue(function()
update_list(moving_adjacent)
if g.state.empty_text == "~" then g.state.empty_text = "empty directory" end
cache:append_history()
if type(moving_adjacent) == 'number' and moving_adjacent < 0 then cache:pop()
else cache:push() end
if not cache.traversal_stack[1] then cache:push() end
ass.update_ass()
end)
return g.state.co
end
return {
rescan = rescan,
scan_directory = parse_directory,
choose_and_parse = choose_and_parse,
}

View File

@@ -1,28 +0,0 @@
local directory_movement = require 'modules.navigation.directory-movement'
local fb = require 'modules.apis.fb'
local fb_utils = require 'modules.utils'
local observers ={}
--saves the directory and name of the currently playing file
function observers.current_directory(_, filepath)
directory_movement.set_current_file(filepath)
end
function observers.dvd_device(_, device)
if not device or device == "" then device = '/dev/dvd' end
fb.register_directory_mapping(fb_utils.absolute_path(device), '^dvd://.*', true)
end
function observers.bd_device(_, device)
if not device or device == '' then device = '/dev/bd' end
fb.register_directory_mapping(fb_utils.absolute_path(device), '^bd://.*', true)
end
function observers.cd_device(_, device)
if not device or device == '' then device = '/dev/cdrom' end
fb.register_directory_mapping(fb_utils.absolute_path(device), '^cdda://.*', true)
end
return observers

View File

@@ -1,147 +0,0 @@
local utils = require 'mp.utils'
local opt = require 'mp.options'
local o = {
--root directories
root = "~/",
--characters to use as separators
root_separators = ",;",
--number of entries to show on the screen at once
num_entries = 20,
--wrap the cursor around the top and bottom of the list
wrap = false,
--only show files compatible with mpv
filter_files = true,
--experimental feature that recurses directories concurrently when
--appending items to the playlist
concurrent_recursion = false,
--maximum number of recursions that can run concurrently
max_concurrency = 16,
--enable custom keybinds
custom_keybinds = false,
--blacklist compatible files, it's recommended to use this rather than to edit the
--compatible list directly. A semicolon separated list of extensions without spaces
extension_blacklist = "",
--add extra file extensions
extension_whitelist = "",
--files with these extensions will be added as additional audio tracks for the current file instead of appended to the playlist
audio_extensions = "mka,dts,dtshd,dts-hd,truehd,true-hd",
--files with these extensions will be added as additional subtitle tracks instead of appended to the playlist
subtitle_extensions = "etf,etf8,utf-8,idx,sub,srt,rt,ssa,ass,mks,vtt,sup,scc,smi,lrc,pgs",
--filter dot directories like .config
--most useful on linux systems
filter_dot_dirs = false,
filter_dot_files = false,
--substitude forward slashes for backslashes when appending a local file to the playlist
--potentially useful on windows systems
substitute_backslash = false,
--interpret backslashes `\` in paths as forward slashes `/`
--this is useful on Windows, which natively uses backslashes.
--As backslashes are valid filename characters in Unix systems this could
--cause mangled paths, though such filenames are rare.
--Use `yes` and `no` to enable/disable. `auto` tries to use the mpv `platform`
--property (mpv v0.36+) to decide. If the property is unavailable it defaults to `yes`.
normalise_backslash = 'auto',
--this option reverses the behaviour of the alt+ENTER keybind
--when disabled the keybind is required to enable autoload for the file
--when enabled the keybind disables autoload for the file
autoload = false,
--if autoload is triggered by selecting the currently playing file, then
--the current file will have it's watch-later config saved before being closed
--essentially the current file will not be restarted
autoload_save_current = true,
--when opening the browser in idle mode prefer the current working directory over the root
--note that the working directory is set as the 'current' directory regardless, so `home` will
--move the browser there even if this option is set to false
default_to_working_directory = false,
--when moving up a directory do not stop on empty protocol schemes like `ftp://`
--e.g. moving up from `ftp://localhost/` will move straight to the root instead of `ftp://`
skip_protocol_schemes = true,
--map optical device paths to their respective file paths,
--e.g. mapping bd:// to the value of the bluray-device property
map_bd_device = true,
map_dvd_device = true,
map_cdda_device = true,
--allows custom icons be set for the folder and cursor
--the `\h` character is a hard space to add padding between the symbol and the text
folder_icon = [[{\p1}m 6.52 0 l 1.63 0 b 0.73 0 0.01 0.73 0.01 1.63 l 0 11.41 b 0 12.32 0.73 13.05 1.63 13.05 l 14.68 13.05 b 15.58 13.05 16.31 12.32 16.31 11.41 l 16.31 3.26 b 16.31 2.36 15.58 1.63 14.68 1.63 l 8.15 1.63{\p0}\h]],
cursor_icon = [[{\p1}m 14.11 6.86 l 0.34 0.02 b 0.25 -0.02 0.13 -0 0.06 0.08 b -0.01 0.16 -0.02 0.28 0.04 0.36 l 3.38 5.55 l 3.38 5.55 3.67 6.15 3.81 6.79 3.79 7.45 3.61 8.08 3.39 8.5l 0.04 13.77 b -0.02 13.86 -0.01 13.98 0.06 14.06 b 0.11 14.11 0.17 14.13 0.24 14.13 b 0.27 14.13 0.31 14.13 0.34 14.11 l 14.11 7.28 b 14.2 7.24 14.25 7.16 14.25 7.07 b 14.25 6.98 14.2 6.9 14.11 6.86{\p0}\h]],
--enable addons
addons = false,
addon_directory = "~~/script-modules/file-browser-addons",
--directory to load external modules - currently just user-input-module
module_directory = "~~/script-modules",
--turn the OSC idle screen off and on when opening and closing the browser
toggle_idlescreen = false,
--Set the current open status of the browser in the `file_browser/open` field of the `user-data` property.
--This property is only available in mpv v0.36+.
set_user_data = true,
--Set the current open status of the browser in the `file_browser-open` field of the `shared-script-properties` property.
--This property is deprecated. When it is removed in mpv v0.37 file-browser will automatically ignore this option.
set_shared_script_properties = false,
--force file-browser to use a specific text alignment (default: top-left)
--uses ass tag alignment numbers: https://aegi.vmoe.info/docs/3.0/ASS_Tags/#index23h3
--set to 0 to use the default mpv osd-align options
alignment = 7,
--style settings
format_string_header = '%q\\N----------------------------------------------------',
format_string_topwrapper = '%< item(s) above\\N',
format_string_bottomwrapper = '\\N%> item(s) remaining',
font_bold_header = true,
font_opacity_selection_marker = "99",
scaling_factor_base = 1,
scaling_factor_header = 1.4,
scaling_factor_wrappers = 0.64,
font_name_header = "",
font_name_body = "",
font_name_wrappers = "",
font_name_folder = "",
font_name_cursor = "",
font_colour_header = "00ccff",
font_colour_body = "ffffff",
font_colour_wrappers = "00ccff",
font_colour_cursor = "00ccff",
font_colour_multiselect = "fcad88",
font_colour_selected = "fce788",
font_colour_playing = "33ff66",
font_colour_playing_multiselected = "22b547"
}
opt.read_options(o, 'file_browser')
o.set_shared_script_properties = o.set_shared_script_properties and utils.shared_script_property_set
return o

View File

@@ -1,44 +0,0 @@
-- This file is an internal file-browser addon.
-- It should not be imported like a normal module.
local msg = require 'mp.msg'
local utils = require 'mp.utils'
--parser object for native filesystems
local file_parser = {
name = "file",
priority = 110,
api_version = '1.0.0',
}
--try to parse any directory except for the root
function file_parser:can_parse(directory)
return directory ~= ''
end
--scans the given directory using the mp.utils.readdir function
function file_parser:parse(directory)
local new_list = {}
local list1 = utils.readdir(directory, 'dirs')
if list1 == nil then return nil end
--sorts folders and formats them into the list of directories
for i=1, #list1 do
local item = list1[i]
msg.trace(item..'/')
table.insert(new_list, {name = item..'/', type = 'dir'})
end
--appends files to the list of directory items
local list2 = utils.readdir(directory, 'files')
for i=1, #list2 do
local item = list2[i]
msg.trace(item)
table.insert(new_list, {name = item, type = 'file'})
end
return new_list
end
return file_parser

View File

@@ -1,25 +0,0 @@
local g = require 'modules.globals'
--parser object for the root
--not inserted to the parser list as it has special behaviour
--it does get added to parsers under its ID to prevent confusing duplicates
local root_parser = {
name = "root",
priority = math.huge,
api_version = '1.0.0',
}
function root_parser:can_parse(directory)
return directory == ''
end
--we return the root directory exactly as setup
function root_parser:parse()
return g.root, {
sorted = true,
filtered = true,
}
end
return root_parser

View File

@@ -1,292 +0,0 @@
------------------------------------------------------------------------------------------
---------------------------------File/Playlist Opening------------------------------------
------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------
local mp = require 'mp'
local msg = require 'mp.msg'
local utils = require 'mp.utils'
local o = require 'modules.options'
local g = require 'modules.globals'
local fb_utils = require 'modules.utils'
local ass = require 'modules.ass'
local cursor = require 'modules.navigation.cursor'
local controls = require 'modules.controls'
local scanning = require 'modules.navigation.scanning'
local movement = require 'modules.navigation.directory-movement'
local state = g.state
-- In mpv v0.38 a new index argument was added to the loadfile command.
-- For some crazy reason this new argument is placed before the existing options
-- argument, breaking any scripts that used it. This function finds the correct index
-- for the options argument using the `command-list` property.
local function get_loadfile_options_arg_index()
local command_list = mp.get_property_native('command-list', {})
for _, command in ipairs(command_list) do
if command.name == 'loadfile' then
for i, arg in ipairs(command.args or {}) do
if arg.name == 'options' then
return i
end
end
end
end
return 3
end
local LEGACY_LOADFILE_SYNTAX = get_loadfile_options_arg_index() == 3
-- A wrapper around loadfile to handle the syntax changes introduced in mpv v0.38.
local function legacy_loadfile_wrapper(file, flag, options)
if LEGACY_LOADFILE_SYNTAX then
return mp.command_native({"loadfile", file, flag, options})
else
return mp.command_native({"loadfile", file, flag, -1, options})
end
end
--adds a file to the playlist and changes the flag to `append-play` in preparation
--for future items
local function loadfile(file, opts, mpv_opts)
if o.substitute_backslash and not fb_utils.get_protocol(file) then
file = file:gsub("/", "\\")
end
if opts.flag == "replace" then msg.verbose("Playling file", file)
else msg.verbose("Appending", file, "to the playlist") end
if mpv_opts then
msg.debug('Settings opts on', file, ':', utils.to_string(mpv_opts))
end
if not legacy_loadfile_wrapper(file, opts.flag, mpv_opts) then msg.warn(file) end
opts.flag = "append-play"
opts.items_appended = opts.items_appended + 1
end
--this function recursively loads directories concurrently in separate coroutines
--results are saved in a tree of tables that allows asynchronous access
local function concurrent_loadlist_parse(directory, load_opts, prev_dirs, item_t)
--prevents infinite recursion from the item.path or opts.directory fields
if prev_dirs[directory] then return end
prev_dirs[directory] = true
local list, list_opts = scanning.scan_directory(directory, { source = "loadlist" })
if list == g.root then return end
--if we can't parse the directory then append it and hope mpv fares better
if list == nil then
msg.warn("Could not parse", directory, "appending to playlist anyway")
item_t.type = "file"
return
end
directory = list_opts.directory or directory
if directory == "" then return end
--we must declare these before we start loading sublists otherwise the append thread will
--need to wait until the whole list is loaded (when synchronous IO is used)
item_t._sublist = list or {}
list._directory = directory
--launches new parse operations for directories, each in a different coroutine
for _, item in ipairs(list) do
if fb_utils.parseable_item(item) then
fb_utils.coroutine.run(concurrent_loadlist_wrapper, fb_utils.get_new_directory(item, directory), load_opts, prev_dirs, item)
end
end
return true
end
--a wrapper function that ensures the concurrent_loadlist_parse is run correctly
function concurrent_loadlist_wrapper(directory, opts, prev_dirs, item)
--ensures that only a set number of concurrent parses are operating at any one time.
--the mpv event queue is seemingly limited to 1000 items, but only async mpv actions like
--command_native_async should use that, events like mp.add_timeout (which coroutine.sleep() uses) should
--be handled enturely on the Lua side with a table, which has a significantly larger maximum size.
while (opts.concurrency > o.max_concurrency) do
fb_utils.coroutine.sleep(0.1)
end
opts.concurrency = opts.concurrency + 1
local success = concurrent_loadlist_parse(directory, opts, prev_dirs, item)
opts.concurrency = opts.concurrency - 1
if not success then item._sublist = {} end
if coroutine.status(opts.co) == "suspended" then fb_utils.coroutine.resume_err(opts.co) end
end
--recursively appends items to the playlist, acts as a consumer to the previous functions producer;
--if the next directory has not been parsed this function will yield until the parse has completed
local function concurrent_loadlist_append(list, load_opts)
local directory = list._directory
for _, item in ipairs(list) do
if not g.sub_extensions[ fb_utils.get_extension(item.name, "") ]
and not g.audio_extensions[ fb_utils.get_extension(item.name, "") ]
then
while (not item._sublist and fb_utils.parseable_item(item)) do
coroutine.yield()
end
if fb_utils.parseable_item(item) then
concurrent_loadlist_append(item._sublist, load_opts)
else
loadfile(fb_utils.get_full_path(item, directory), load_opts, item.mpv_options)
end
end
end
end
--recursive function to load directories using the script custom parsers
--returns true if any items were appended to the playlist
local function custom_loadlist_recursive(directory, load_opts, prev_dirs)
--prevents infinite recursion from the item.path or opts.directory fields
if prev_dirs[directory] then return end
prev_dirs[directory] = true
local list, opts = scanning.scan_directory(directory, { source = "loadlist" })
if list == g.root then return end
--if we can't parse the directory then append it and hope mpv fares better
if list == nil then
msg.warn("Could not parse", directory, "appending to playlist anyway")
loadfile(directory, load_opts.flag)
return true
end
directory = opts.directory or directory
if directory == "" then return end
for _, item in ipairs(list) do
if not g.sub_extensions[ fb_utils.get_extension(item.name, "") ]
and not g.audio_extensions[ fb_utils.get_extension(item.name, "") ]
then
if fb_utils.parseable_item(item) then
custom_loadlist_recursive( fb_utils.get_new_directory(item, directory) , load_opts, prev_dirs)
else
local path = fb_utils.get_full_path(item, directory)
loadfile(path, load_opts, item.mpv_options)
end
end
end
end
--a wrapper for the custom_loadlist_recursive function
local function loadlist(item, opts)
local dir = fb_utils.get_full_path(item, opts.directory)
local num_items = opts.items_appended
if o.concurrent_recursion then
item = fb_utils.copy_table(item)
opts.co = fb_utils.coroutine.assert()
opts.concurrency = 0
--we need the current coroutine to suspend before we run the first parse operation, so
--we schedule the coroutine to run on the mpv event queue
mp.add_timeout(0, function()
fb_utils.coroutine.run(concurrent_loadlist_wrapper, dir, opts, {}, item)
end)
concurrent_loadlist_append({item, _directory = opts.directory}, opts)
else
custom_loadlist_recursive(dir, opts, {})
end
if opts.items_appended == num_items then msg.warn(dir, "contained no valid files") end
end
--load playlist entries before and after the currently playing file
local function autoload_dir(path, opts)
if o.autoload_save_current and path == g.current_file.path then
mp.commandv("write-watch-later-config") end
--loads the currently selected file, clearing the playlist in the process
loadfile(path, opts)
local pos = 1
local file_count = 0
for _,item in ipairs(state.list) do
if item.type == "file"
and not g.sub_extensions[ fb_utils.get_extension(item.name, "") ]
and not g.audio_extensions[ fb_utils.get_extension(item.name, "") ]
then
local p = fb_utils.get_full_path(item)
if p == path then pos = file_count
else loadfile( p, opts, item.mpv_options) end
file_count = file_count + 1
end
end
mp.commandv("playlist-move", 0, pos+1)
end
--runs the loadfile or loadlist command
local function open_item(item, opts)
if fb_utils.parseable_item(item) then
return loadlist(item, opts)
end
local path = fb_utils.get_full_path(item, opts.directory)
if g.sub_extensions[ fb_utils.get_extension(item.name, "") ] then
mp.commandv("sub-add", path, opts.flag == "replace" and "select" or "auto")
elseif g.audio_extensions[ fb_utils.get_extension(item.name, "") ] then
mp.commandv("audio-add", path, opts.flag == "replace" and "select" or "auto")
else
if opts.autoload then autoload_dir(path, opts)
else loadfile(path, opts, item.mpv_options) end
end
end
--handles the open options as a coroutine
--once loadfile has been run we can no-longer guarantee synchronous execution - the state values may change
--therefore, we must ensure that any state values that could be used after a loadfile call are saved beforehand
local function open_file_coroutine(opts)
if not state.list[state.selected] then return end
if opts.flag == 'replace' then controls.close() end
--we want to set the idle option to yes to ensure that if the first item
--fails to load then the player has a chance to attempt to load further items (for async append operations)
local idle = mp.get_property("idle", "once")
mp.set_property("idle", "yes")
--handles multi-selection behaviour
if next(state.selection) then
local selection = fb_utils.sort_keys(state.selection)
--reset the selection after
state.selection = {}
cursor.disable_select_mode()
ass.update_ass()
--the currently selected file will be loaded according to the flag
--the flag variable will be switched to append once a file is loaded
for i=1, #selection do
open_item(selection[i], opts)
end
else
local item = state.list[state.selected]
if opts.flag == "replace" then movement.down_dir() end
open_item(item, opts)
end
if mp.get_property("idle") == "yes" then mp.set_property("idle", idle) end
end
--opens the selelected file(s)
local function open_file(flag, autoload)
fb_utils.coroutine.run(open_file_coroutine, {
flag = flag,
autoload = (autoload ~= o.autoload and flag == "replace"),
directory = state.directory,
items_appended = 0
})
end
return {
add_files = open_file,
}

View File

@@ -1,93 +0,0 @@
local mp = require 'mp'
local msg = require 'mp.msg'
local utils = require 'mp.utils'
local o = require 'modules.options'
local g = require 'modules.globals'
local fb_utils = require 'modules.utils'
local scanning = require 'modules.navigation.scanning'
local script_messages = {}
--allows other scripts to request directory contents from file-browser
function script_messages.get_directory_contents(directory, response_str)
fb_utils.coroutine.run(function()
if not directory then msg.error("did not receive a directory string"); return end
if not response_str then msg.error("did not receive a response string"); return end
directory = mp.command_native({"expand-path", directory}, "")
if directory ~= "" then directory = fb_utils.fix_path(directory, true) end
msg.verbose(("recieved %q from 'get-directory-contents' script message - returning result to %q"):format(directory, response_str))
directory = fb_utils.resolve_directory_mapping(directory)
local list, opts = scanning.scan_directory(directory, { source = "script-message" } )
if opts then opts.API_VERSION = g.API_VERSION end
local err
list, err = fb_utils.format_json_safe(list)
if not list then msg.error(err) end
opts, err = fb_utils.format_json_safe(opts)
if not opts then msg.error(err) end
mp.commandv("script-message", response_str, list or "", opts or "")
end)
end
--a helper script message for custom keybinds
--substitutes any '=>' arguments for 'script-message'
--makes chaining script-messages much easier
function script_messages.chain(...)
local command = table.pack('script-message', ...)
for i, v in ipairs(command) do
if v == '=>' then command[i] = 'script-message' end
end
mp.commandv(table.unpack(command))
end
--a helper script message for custom keybinds
--sends a command after the specified delay
function script_messages.delay_command(delay, ...)
local command = table.pack(...)
local success, err = pcall(mp.add_timeout, fb_utils.evaluate_string('return '..delay), function() mp.commandv(table.unpack(command)) end)
if not success then return msg.error(err) end
end
--a helper script message for custom keybinds
--sends a command only if the given expression returns true
function script_messages.conditional_command(condition, ...)
local command = table.pack(...)
fb_utils.coroutine.run(function()
if fb_utils.evaluate_string('return '..condition) == true then mp.commandv(table.unpack(command)) end
end)
end
--a helper script message for custom keybinds
--extracts lua expressions from the command and evaluates them
--expressions must be surrounded by !{}. Another ! before the { will escape the evaluation
function script_messages.evaluate_expressions(...)
local args = table.pack(...)
fb_utils.coroutine.run(function()
for i, arg in ipairs(args) do
args[i] = arg:gsub('(!+)(%b{})', function(lead, expression)
if #lead % 2 == 0 then return string.rep('!', #lead/2)..expression end
local eval = fb_utils.evaluate_string('return '..expression:sub(2, -2))
return type(eval) == "table" and utils.to_string(eval) or tostring(eval)
end)
end
mp.commandv(table.unpack(args))
end)
end
--a helper function for custom-keybinds
--concatenates the command arguments with newlines and runs the
--string as a statement of code
function script_messages.run_statement(...)
local statement = table.concat(table.pack(...), '\n')
fb_utils.coroutine.run(fb_utils.evaluate_string, statement)
end
return script_messages

View File

@@ -1,52 +0,0 @@
local mp = require 'mp'
local o = require 'modules.options'
local g = require 'modules.globals'
local fb_utils = require 'modules.utils'
--sets up the compatible extensions list
local function setup_extensions_list()
--setting up subtitle extensions
for ext in fb_utils.iterate_opt(o.subtitle_extensions:lower()) do
g.sub_extensions[ext] = true
g.extensions[ext] = true
end
--setting up audio extensions
for ext in fb_utils.iterate_opt(o.audio_extensions:lower()) do
g.audio_extensions[ext] = true
g.extensions[ext] = true
end
--adding file extensions to the set
for _, ext in ipairs(g.compatible_file_extensions) do
g.extensions[ext] = true
end
--adding extra extensions on the whitelist
for str in fb_utils.iterate_opt(o.extension_whitelist:lower()) do
g.extensions[str] = true
end
--removing extensions that are in the blacklist
for str in fb_utils.iterate_opt(o.extension_blacklist:lower()) do
g.extensions[str] = nil
end
end
--splits the string into a table on the separators
local function setup_root()
for str in fb_utils.iterate_opt(o.root) do
local path = mp.command_native({'expand-path', str})
path = fb_utils.fix_path(path, true)
local temp = {name = path, type = 'dir', label = str, ass = fb_utils.ass_escape(str, true)}
g.root[#g.root+1] = temp
end
end
return {
extensions_list = setup_extensions_list,
root = setup_root,
}

View File

@@ -1,490 +0,0 @@
--------------------------------------------------------------------------------------------------------
-----------------------------------------Utility Functions----------------------------------------------
---------------------------------------Part of the addon API--------------------------------------------
--------------------------------------------------------------------------------------------------------
local mp = require 'mp'
local msg = require 'mp.msg'
local utils = require 'mp.utils'
local o = require 'modules.options'
local g = require 'modules.globals'
local input_loaded, input = pcall(require, 'mp.input')
local user_input_loaded, user_input = pcall(require, 'user-input-module')
--creates a table for the API functions
--adds one metatable redirect to prevent addon authors from accidentally breaking file-browser
local fb_utils = { API_VERSION = g.API_VERSION }
fb_utils.list = {}
fb_utils.coroutine = {}
--implements table.pack if on lua 5.1
if not table.pack then
table.unpack = unpack
---@diagnostic disable-next-line: duplicate-set-field
function table.pack(...)
local t = {n = select("#", ...), ...}
return t
end
end
-- returns the index of the given item in the table
-- return -1 if item does not exist
function fb_utils.list.indexOf(t, item, from_index)
for i = from_index or 1, #t, 1 do
if t[i] == item then return i end
end
return -1
end
--returns whether or not the given table contains an entry that
--causes the given function to evaluate to true
function fb_utils.list.some(t, fn)
for i, v in ipairs(t) do
if fn(v, i, t) then return true end
end
return false
end
-- Creates a new table populated with the results of
-- calling a provided function on every element in t.
function fb_utils.list.map(t, fn)
local new_t = {}
for i, v in ipairs(t) do
new_t[i] = fn(v, i, t)
end
return new_t
end
--prints an error message and a stack trace
--accepts an error object and optionally a coroutine
--can be passed directly to xpcall
function fb_utils.traceback(errmsg, co)
if co then
msg.warn(debug.traceback(co))
else
msg.warn(debug.traceback("", 2))
end
msg.error(errmsg)
end
--returns a table that stores the given table t as the __index in its metatable
--creates a prototypally inherited table
function fb_utils.redirect_table(t)
return setmetatable({}, { __index = t })
end
function fb_utils.set_prototype(t, proto)
return setmetatable(t, { __index = proto })
end
--prints an error if a coroutine returns an error
--unlike the next function this one still returns the results of coroutine.resume()
function fb_utils.coroutine.resume_catch(...)
local returns = table.pack(coroutine.resume(...))
if not returns[1] and returns[2] ~= g.ABORT_ERROR then
fb_utils.traceback(returns[2], select(1, ...))
end
return table.unpack(returns, 1, returns.n)
end
--resumes a coroutine and prints an error if it was not sucessful
function fb_utils.coroutine.resume_err(...)
local success, err = coroutine.resume(...)
if not success and err ~= g.ABORT_ERROR then
fb_utils.traceback(err, select(1, ...))
end
return success
end
--in lua 5.1 there is only one return value which will be nil if run from the main thread
--in lua 5.2 main will be true if running from the main thread
function fb_utils.coroutine.assert(err)
local co, main = coroutine.running()
assert(not main and co, err or "error - function must be executed from within a coroutine")
return co
end
-- Creates a callback function to resume the current coroutine with the given time limit.
-- If the time limit expires the coroutine will be resumed. The first return value will be true
-- if the callback was resumed within the time limit and false otherwise.
-- If time_limit is falsy then there will be no time limit and there will be no additional return value.
function fb_utils.coroutine.callback(time_limit)
local co = fb_utils.coroutine.assert("cannot create a coroutine callback for the main thread")
local timer = time_limit and mp.add_timeout(time_limit, function ()
msg.debug("time limit on callback expired")
fb_utils.coroutine.resume_err(co, false)
end)
return function(...)
if timer then
if not timer:is_enabled() then return
else timer:kill() end
return fb_utils.coroutine.resume_err(co, true, ...)
end
return fb_utils.coroutine.resume_err(co, ...)
end
end
--puts the current coroutine to sleep for the given number of seconds
function fb_utils.coroutine.sleep(n)
mp.add_timeout(n, fb_utils.coroutine.callback())
coroutine.yield()
end
--Runs the given function in a coroutine, passing through any additional arguments.
--Does not run the coroutine immediately, instead it ques the coroutine to run when the thread is next idle.
--Returns the coroutine object so that the caller can act on it before it is run.
function fb_utils.coroutine.queue(fn, ...)
local co = coroutine.create(fn)
local args = table.pack(...)
mp.add_timeout(0, function() fb_utils.coroutine.resume_err(co, table.unpack(args, 1, args.n)) end)
return co
end
--runs the given function in a coroutine, passing through any additional arguments
--this is for triggering an event in a coroutine
function fb_utils.coroutine.run(fn, ...)
local co = coroutine.create(fn)
fb_utils.coroutine.resume_err(co, ...)
end
--get the full path for the current file
function fb_utils.get_full_path(item, dir)
if item.path then return item.path end
return (dir or g.state.directory)..item.name
end
--gets the path for a new subdirectory, redirects if the path field is set
--returns the new directory path and a boolean specifying if a redirect happened
function fb_utils.get_new_directory(item, directory)
if item.path and item.redirect ~= false then return item.path, true end
if directory == "" then return item.name end
if string.sub(directory, -1) == "/" then return directory..item.name end
return directory.."/"..item.name
end
--returns the file extension of the given file
function fb_utils.get_extension(filename, def)
return string.lower(filename):match("%.([^%./]+)$") or def
end
--returns the protocol scheme of the given url, or nil if there is none
function fb_utils.get_protocol(filename, def)
return string.lower(filename):match("^(%a[%w+-.]*)://") or def
end
--formats strings for ass handling
--this function is based on a similar function from https://github.com/mpv-player/mpv/blob/master/player/lua/console.lua#L110
function fb_utils.ass_escape(str, replace_newline)
if replace_newline == true then replace_newline = "\\\239\187\191n" end
--escape the invalid single characters
str = string.gsub(str, '[\\{}\n]', {
-- There is no escape for '\' in ASS (I think?) but '\' is used verbatim if
-- it isn't followed by a recognised character, so add a zero-width
-- non-breaking space
['\\'] = '\\\239\187\191',
['{'] = '\\{',
['}'] = '\\}',
-- Precede newlines with a ZWNBSP to prevent ASS's weird collapsing of
-- consecutive newlines
['\n'] = '\239\187\191\\N',
})
-- Turn leading spaces into hard spaces to prevent ASS from stripping them
str = str:gsub('\\N ', '\\N\\h')
str = str:gsub('^ ', '\\h')
if replace_newline then
str = str:gsub("\\N", replace_newline)
end
return str
end
--escape lua pattern characters
function fb_utils.pattern_escape(str)
return string.gsub(str, "([%^%$%(%)%%%.%[%]%*%+%-])", "%%%1")
end
--standardises filepaths across systems
function fb_utils.fix_path(str, is_directory)
if str == '' then return str end
if o.normalise_backslash == 'yes' or (o.normalise_backslash == 'auto' and g.PLATFORM == 'windows') then
str = string.gsub(str, [[\]],[[/]])
end
str = str:gsub([[/%./]], [[/]])
if is_directory and str:sub(-1) ~= '/' then str = str..'/' end
return str
end
--wrapper for utils.join_path to handle protocols
function fb_utils.join_path(working, relative)
return fb_utils.get_protocol(relative) and relative or utils.join_path(working, relative)
end
--converts the given path into an absolute path and normalises it using fb_utils.fix_path
function fb_utils.absolute_path(path)
local absolute_path = fb_utils.join_path(mp.get_property('working-directory', ''), path)
return fb_utils.fix_path(absolute_path)
end
--sorts the table lexicographically ignoring case and accounting for leading/non-leading zeroes
--the number format functionality was proposed by github user twophyro, and was presumably taken
--from here: http://notebook.kulchenko.com/algorithms/alphanumeric-natural-sorting-for-humans-in-lua
function fb_utils.sort(t)
local function padnum(n, d)
return #d > 0 and ("%03d%s%.12f"):format(#n, n, tonumber(d) / (10 ^ #d))
or ("%03d%s"):format(#n, n)
end
--appends the letter d or f to the start of the comparison to sort directories and folders as well
local tuples = {}
for i, f in ipairs(t) do
tuples[i] = {f.type:sub(1, 1) .. (f.label or f.name):lower():gsub("0*(%d+)%.?(%d*)", padnum), f}
end
table.sort(tuples, function(a, b)
return a[1] == b[1] and #b[2] < #a[2] or a[1] < b[1]
end)
for i, tuple in ipairs(tuples) do t[i] = tuple[2] end
return t
end
function fb_utils.valid_dir(dir)
if o.filter_dot_dirs and string.sub(dir, 1, 1) == "." then return false end
return true
end
function fb_utils.valid_file(file)
if o.filter_dot_files and (string.sub(file, 1, 1) == ".") then return false end
if o.filter_files and not g.extensions[ fb_utils.get_extension(file, "") ] then return false end
return true
end
--returns whether or not the item can be parsed
function fb_utils.parseable_item(item)
return item.type == "dir" or g.parseable_extensions[fb_utils.get_extension(item.name, "")]
end
-- Takes a directory string and resolves any directory mappings,
-- returning the resolved directory.
function fb_utils.resolve_directory_mapping(path)
if not path then return path end
for mapping, target in pairs(g.directory_mappings) do
local start, finish = string.find(path, mapping)
if start then
msg.debug('mapping', mapping, 'found for', path, 'changing to', target)
-- if the mapping is an exact match then return the target as is
if finish == #path then return target end
-- else make sure the path is correctly formatted
target = fb_utils.fix_path(target, true)
return string.gsub(path, mapping, target)
end
end
return path
end
--removes items and folders from the list
--this is for addons which can't filter things during their normal processing
function fb_utils.filter(t)
local max = #t
local top = 1
for i = 1, max do
local temp = t[i]
t[i] = nil
if ( temp.type == "dir" and fb_utils.valid_dir(temp.label or temp.name) ) or
( temp.type == "file" and fb_utils.valid_file(temp.label or temp.name) )
then
t[top] = temp
top = top+1
end
end
return t
end
--returns a string iterator that uses the root separators
function fb_utils.iterate_opt(str)
return string.gmatch(str, "([^"..fb_utils.pattern_escape(o.root_separators).."]+)")
end
--sorts a table into an array of selected items in the correct order
--if a predicate function is passed, then the item will only be added to
--the table if the function returns true
function fb_utils.sort_keys(t, include_item)
local keys = {}
for k in pairs(t) do
local item = g.state.list[k]
if not include_item or include_item(item) then
item.index = k
keys[#keys+1] = item
end
end
table.sort(keys, function(a,b) return a.index < b.index end)
return keys
end
--Uses a loop to get the length of an array. The `#` operator is undefined if there
--are gaps in the array, this ensures there are none as expected by the mpv node function.
local function get_length(t)
local i = 1
while t[i] do i = i+1 end
return i - 1
end
--recursively removes elements of the table which would cause
--utils.format_json to throw an error
local function json_safe_recursive(t)
if type(t) ~= "table" then return t end
local array_length = get_length(t)
local isarray = array_length > 0
for key, value in pairs(t) do
local ktype = type(key)
local vtype = type(value)
if vtype ~= "userdata" and vtype ~= "function" and vtype ~= "thread"
and (( isarray and ktype == "number" and key <= array_length)
or (not isarray and ktype == "string"))
then
t[key] = json_safe_recursive(t[key])
elseif key then
t[key] = nil
if isarray then array_length = get_length(t) end
end
end
return t
end
--formats a table into a json string but ensures there are no invalid datatypes inside the table first
function fb_utils.format_json_safe(t)
--operate on a copy of the table to prevent any data loss in the original table
t = json_safe_recursive(fb_utils.copy_table(t))
local success, result, err = pcall(utils.format_json, t)
if success then return result, err
else return nil, result end
end
--evaluates and runs the given string in both Lua 5.1 and 5.2
--the name argument is used for error reporting
--provides the mpv modules and the fb module to the string
function fb_utils.evaluate_string(str, chunkname, custom_env, env_defaults)
local env
if env_defaults ~= false then
env = fb_utils.redirect_table(_G)
env.mp = fb_utils.redirect_table(mp)
env.msg = fb_utils.redirect_table(msg)
env.utils = fb_utils.redirect_table(utils)
env.fb = fb_utils.redirect_table(fb_utils)
env.input = input_loaded and fb_utils.redirect_table(input)
env.user_input = user_input_loaded and fb_utils.redirect_table(user_input)
env = fb_utils.set_prototype(custom_env or {}, env)
else
env = custom_env or {}
end
local chunk, err
if setfenv then
chunk, err = loadstring(str, chunkname)
if chunk then setfenv(chunk, env) end
else
chunk, err = load(str, chunkname, 't', env)
end
if not chunk then
msg.warn('failed to load string:', str)
msg.error(err)
chunk = function() return nil end
end
return chunk()
end
--copies a table without leaving any references to the original
--uses a structured clone algorithm to maintain cyclic references
local function copy_table_recursive(t, references, depth)
if type(t) ~= "table" or depth == 0 then return t end
if references[t] then return references[t] end
local copy = setmetatable({}, { __original = t })
references[t] = copy
for key, value in pairs(t) do
key = copy_table_recursive(key, references, depth - 1)
copy[key] = copy_table_recursive(value, references, depth - 1)
end
return copy
end
--a wrapper around copy_table to provide the reference table
function fb_utils.copy_table(t, depth)
--this is to handle cyclic table references
return copy_table_recursive(t, {}, depth or math.huge)
end
--functions to replace custom-keybind codes
fb_utils.code_fns = {
["%"] = "%",
f = function(item, s) return item and fb_utils.get_full_path(item, s.directory) or "" end,
n = function(item, s) return item and (item.label or item.name) or "" end,
i = function(item, s)
local i = fb_utils.list.indexOf(s.list, item)
return i ~= -1 and ('%0'..math.ceil(math.log10(#s.list))..'d'):format(i) or 0
end,
j = function (item, s)
return fb_utils.list.indexOf(s.list, item) ~= -1 and math.abs(fb_utils.list.indexOf( fb_utils.sort_keys(s.selection) , item)) or 0
end,
x = function(_, s) return #s.list or 0 end,
p = function(_, s) return s.directory or "" end,
q = function(_, s) return s.directory == '' and 'ROOT' or s.directory_label or s.directory or "" end,
d = function(_, s) return (s.directory_label or s.directory):match("([^/]+)/?$") or "" end,
r = function(_, s) return s.parser.keybind_name or s.parser.name or "" end,
}
-- programatically creates a pattern that matches any key code
-- this will result in some duplicates but that shouldn't really matter
function fb_utils.get_code_pattern(codes)
local CUSTOM_KEYBIND_CODES = ""
for key in pairs(codes) do CUSTOM_KEYBIND_CODES = CUSTOM_KEYBIND_CODES..key:lower()..key:upper() end
for key in pairs((getmetatable(codes) or {}).__index or {}) do CUSTOM_KEYBIND_CODES = CUSTOM_KEYBIND_CODES..key:lower()..key:upper() end
return('%%%%([%s])'):format(fb_utils.pattern_escape(CUSTOM_KEYBIND_CODES))
end
-- substitutes codes in the given string for other substrings
-- overrides is a map of characters->strings|functions that determines the replacement string is
-- item and state are values passed to functions in the map
-- modifier_fn is given the replacement substrings before they are placed in the main string (the return value is the new replacement string)
function fb_utils.substitute_codes(str, overrides, item, state, modifier_fn)
local replacers = overrides and setmetatable(fb_utils.copy_table(overrides), {__index = fb_utils.code_fns}) or fb_utils.code_fns
item = item or g.state.list[g.state.selected]
state = state or g.state
return (string.gsub(str, fb_utils.get_code_pattern(replacers), function(code)
local result
if type(replacers[code]) == "string" then
result = replacers[code]
--encapsulates the string if using an uppercase code
elseif not replacers[code] then
local lower_fn = replacers[code:lower()]
if not lower_fn then return end
result = string.format("%q", lower_fn(item, state))
else
result = replacers[code](item, state)
end
if modifier_fn then return modifier_fn(result) end
return result
end))
end
return fb_utils

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 975 KiB

View File

@@ -1,97 +0,0 @@
local utils = require 'mp.utils'
local lastopenFileName = "lastopen.json"
local styleOn = mp.get_property("osd-ass-cc/0")
local styleOff = mp.get_property("osd-ass-cc/1")
-- Check if the operating system is Windows
function isWindows()
local windir = os.getenv("windir")
return (windir~=nil)
end
-- Get the filepath of a file from the mpv config folder
local function getFilepath(filename)
if isWindows() then
return os.getenv("APPDATA"):gsub("\\", "/") .. "/mpv/" .. filename
else
return os.getenv("HOME") .. "/.config/mpv/" .. filename
end
end
local options = {
path = getFilepath(lastopenFileName)
}
-- Save a table as a JSON file file
-- Returns true if successful
function saveTable(t, path)
local contents = utils.format_json(t)
local file = io.open(path .. ".tmp", "wb")
file:write(contents)
io.close(file)
os.remove(path)
os.rename(path .. ".tmp", path)
return true
end
function file_exists(path)
local file = io.open(path, "r") -- Try to open the file in read mode
if file then
file:close() -- Close the file if it was successfully opened
return true
else
return false
end
end
local function save_data()
local data = {
path = mp.get_property('path'),
time_pos = mp.get_property_number('time-pos')
}
saveTable(data, options.path)
end
function loadData(path)
local contents = ""
local myTable = {}
local file = io.open( path, "r" )
if file then
local contents = file:read( "*a" )
myTable = utils.parse_json(contents);
io.close(file)
return myTable
end
return nil
end
-- Parses a Windows path with backslashes to one with normal slashes
function parsePath(path)
if type(path) == "string" then path, _ = path:gsub("\\", "/") end
return path
end
local function load_data()
local data = loadData(getFilepath(lastopenFileName))
if data then
if data.path and file_exists(data.path) then
mp.commandv("loadfile", parsePath(data.path), "replace", -1)
local message = styleOn.."{\\b1}Last Open load:\n"..data.path.."{\\b0}"..styleOff
mp.osd_message(message)
elseif not file_exists(data.path) then
mp.osd_message('File not found: '..data.path)
else
mp.osd_message('Failed to parse lastopen.json')
end
else
mp.osd_message('No lastopen.json found')
end
end
mp.register_event('start-file', save_data)
mp.register_script_message("lastopen", load_data)

3717
mpv/scripts/modernz.lua Normal file
View File

File diff suppressed because it is too large Load Diff

191
mpv/scripts/mpv-gif.lua Normal file
View File

@@ -0,0 +1,191 @@
-- Original by Ruin0x11
-- Ported to Windows by Scheliux, Dragoner7
-- Create animated GIFs with mpv
-- Requires ffmpeg.
-- Adapted from http://blog.pkh.me/p/21-high-quality-gif-with-ffmpeg.html
-- Usage: "b" to set start frame, "B" to set end frame, "Ctrl+b" to create.
require 'mp.options'
local msg = require 'mp.msg'
local options = {
dir = "C:/Program Files/mpv/gifs",
rez = 600,
fps = 15,
}
read_options(options, "gif")
local fps
-- Check for invalid fps values
-- Can you believe Lua doesn't have a proper ternary operator in the year of our lord 2020?
if options.fps ~= nil and options.fps >= 1 and options.fps < 30 then
fps = options.fps
else
fps = 15
end
-- Set this to the filters to pass into ffmpeg's -vf option.
-- filters="fps=24,scale=320:-1:flags=spline"
filters=string.format("fps=%s,scale='trunc(ih*dar/2)*2:trunc(ih/2)*2',setsar=1/1,scale=%s:-1:flags=spline", fps, options.rez) --change spline to lanczos depending on preference
-- Setup output directory
output_directory=string.gsub(options.dir, '\"', '')
start_time = -1
end_time = -1
palette="%TEMP%palette.png"
-- The roundabout way has to be used due to a some weird
-- behavior with %TEMP% on the subtitles= parameter in ffmpeg
-- on Windowsit needs to be quadruple backslashed
subs = "C:/Users/%USERNAME%/AppData/Local/Temp/subs.srt"
function make_gif_with_subtitles()
make_gif_internal(true)
end
function make_gif()
make_gif_internal(false)
end
function table_length(t)
local count = 0
for _ in pairs(t) do count = count + 1 end
return count
end
function make_gif_internal(burn_subtitles)
local start_time_l = start_time
local end_time_l = end_time
if start_time_l == -1 or end_time_l == -1 or start_time_l >= end_time_l then
mp.osd_message("Invalid start/end time.")
return
end
mp.osd_message("Creating GIF.")
-- shell escape
function esc(s)
return string.gsub(s, '"', '"\\""')
end
function esc_for_sub(s)
s = string.gsub(s, [[\]], [[/]])
s = string.gsub(s, '"', '"\\""')
s = string.gsub(s, ":", [[\\:]])
s = string.gsub(s, "'", [[\\']])
return s
end
local pathname = mp.get_property("path", "")
local trim_filters = esc(filters)
local position = start_time_l
local duration = end_time_l - start_time_l
if burn_subtitles then
-- Determine currently active sub track
local i = 0
local tracks_count = mp.get_property_number("track-list/count")
local subs_array = {}
-- check for subtitle tracks
while i < tracks_count do
local type = mp.get_property(string.format("track-list/%d/type", i))
local selected = mp.get_property(string.format("track-list/%d/selected", i))
-- if it's a sub track, save it
if type == "sub" then
local length = table_length(subs_array)
subs_array[length] = selected == "yes"
end
i = i + 1
end
if table_length(subs_array) > 0 then
local correct_track = 0
-- iterate through saved subtitle tracks until the correct one is found
for index, is_selected in pairs(subs_array) do
if (is_selected) then
correct_track = index
end
end
trim_filters = trim_filters .. string.format(",subtitles=%s:si=%s", esc_for_sub(pathname), correct_track)
end
end
-- first, create the palette
args = string.format('ffmpeg -v warning -ss %s -t %s -i "%s" -vf "%s,palettegen" -y "%s"', position, duration, esc(pathname), esc(trim_filters), esc(palette))
msg.debug(args)
os.execute(args)
-- then, make the gif
local filename = mp.get_property("filename/no-ext")
local file_path = output_directory .. "/" .. filename
-- increment filename
for i=0,999 do
local fn = string.format('%s_%03d.gif',file_path,i)
if not file_exists(fn) then
gifname = fn
break
end
end
if not gifname then
mp.osd_message('No available filenames!')
return
end
local copyts = ""
if burn_subtitles then
copyts = "-copyts"
end
args = string.format('ffmpeg -v warning -ss %s %s -t %s -i "%s" -i "%s" -lavfi "%s [x]; [x][1:v] paletteuse" -y "%s"', position, copyts, duration, esc(pathname), esc(palette), esc(trim_filters), esc(gifname))
os.execute(args)
local ok, err, code = os.rename(gifname, gifname)
if ok then
msg.info("GIF created: " .. gifname)
mp.osd_message("GIF created: " .. gifname)
else
mp.osd_message("Error creating file, check CLI for more info.")
end
end
function set_gif_start()
start_time = mp.get_property_number("time-pos", -1)
mp.osd_message("GIF Start: " .. start_time)
end
function set_gif_end()
end_time = mp.get_property_number("time-pos", -1)
mp.osd_message("GIF End: " .. end_time)
end
function file_exists(name)
local f=io.open(name,"r")
if f~=nil then io.close(f) return true else return false end
end
-- all keybindings here are set to nil on purpose 'cause I modified the keybindings (in input.conf)
mp.add_key_binding(nil, "set_gif_start", set_gif_start)
mp.add_key_binding(nil, "set_gif_end", set_gif_end)
mp.add_key_binding(nil, "make_gif", make_gif)
mp.add_key_binding(nil, "make_gif_with_subtitles", make_gif_with_subtitles) -- making GIFs with subtitles doesn't seem to work

View File

@@ -1,736 +0,0 @@
--[[
Copyright (C) 2017 AMM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
]]--
--[[
mpv_thumbnail_script.lua 0.4.3 - commit 682becf (branch master)
https://github.com/TheAMM/mpv_thumbnail_script
Built on 2020-01-17 00:00:00
]]--
local assdraw = require 'mp.assdraw'
local msg = require 'mp.msg'
local opt = require 'mp.options'
local utils = require 'mp.utils'
-- Determine platform --
ON_WINDOWS = (package.config:sub(1,1) ~= '/')
-- Some helper functions needed to parse the options --
function isempty(v) return (v == false) or (v == nil) or (v == "") or (v == 0) or (type(v) == "table" and next(v) == nil) end
function divmod (a, b)
return math.floor(a / b), a % b
end
-- Better modulo
function bmod( i, N )
return (i % N + N) % N
end
function join_paths(...)
local sep = ON_WINDOWS and "\\" or "/"
local result = "";
for i, p in pairs({...}) do
if p ~= "" then
if is_absolute_path(p) then
result = p
else
result = (result ~= "") and (result:gsub("[\\"..sep.."]*$", "") .. sep .. p) or p
end
end
end
return result:gsub("[\\"..sep.."]*$", "")
end
-- /some/path/file.ext -> /some/path, file.ext
function split_path( path )
local sep = ON_WINDOWS and "\\" or "/"
local first_index, last_index = path:find('^.*' .. sep)
if last_index == nil then
return "", path
else
local dir = path:sub(0, last_index-1)
local file = path:sub(last_index+1, -1)
return dir, file
end
end
function is_absolute_path( path )
local tmp, is_win = path:gsub("^[A-Z]:\\", "")
local tmp, is_unix = path:gsub("^/", "")
return (is_win > 0) or (is_unix > 0)
end
function Set(source)
local set = {}
for _, l in ipairs(source) do set[l] = true end
return set
end
---------------------------
-- More helper functions --
---------------------------
-- Removes all keys from a table, without destroying the reference to it
function clear_table(target)
for key, value in pairs(target) do
target[key] = nil
end
end
function shallow_copy(target)
local copy = {}
for k, v in pairs(target) do
copy[k] = v
end
return copy
end
-- Rounds to given decimals. eg. round_dec(3.145, 0) => 3
function round_dec(num, idp)
local mult = 10^(idp or 0)
return math.floor(num * mult + 0.5) / mult
end
function file_exists(name)
local f = io.open(name, "rb")
if f ~= nil then
local ok, err, code = f:read(1)
io.close(f)
return code == nil
else
return false
end
end
function path_exists(name)
local f = io.open(name, "rb")
if f ~= nil then
io.close(f)
return true
else
return false
end
end
function create_directories(path)
local cmd
if ON_WINDOWS then
cmd = { args = {"cmd", "/c", "mkdir", path} }
else
cmd = { args = {"mkdir", "-p", path} }
end
utils.subprocess(cmd)
end
-- Find an executable in PATH or CWD with the given name
function find_executable(name)
local delim = ON_WINDOWS and ";" or ":"
local pwd = os.getenv("PWD") or utils.getcwd()
local path = os.getenv("PATH")
local env_path = pwd .. delim .. path -- Check CWD first
local result, filename
for path_dir in env_path:gmatch("[^"..delim.."]+") do
filename = join_paths(path_dir, name)
if file_exists(filename) then
result = filename
break
end
end
return result
end
local ExecutableFinder = { path_cache = {} }
-- Searches for an executable and caches the result if any
function ExecutableFinder:get_executable_path( name, raw_name )
name = ON_WINDOWS and not raw_name and (name .. ".exe") or name
if self.path_cache[name] == nil then
self.path_cache[name] = find_executable(name) or false
end
return self.path_cache[name]
end
-- Format seconds to HH.MM.SS.sss
function format_time(seconds, sep, decimals)
decimals = decimals == nil and 3 or decimals
sep = sep and sep or "."
local s = seconds
local h, s = divmod(s, 60*60)
local m, s = divmod(s, 60)
local second_format = string.format("%%0%d.%df", 2+(decimals > 0 and decimals+1 or 0), decimals)
return string.format("%02d"..sep.."%02d"..sep..second_format, h, m, s)
end
-- Format seconds to 1h 2m 3.4s
function format_time_hms(seconds, sep, decimals, force_full)
decimals = decimals == nil and 1 or decimals
sep = sep ~= nil and sep or " "
local s = seconds
local h, s = divmod(s, 60*60)
local m, s = divmod(s, 60)
if force_full or h > 0 then
return string.format("%dh"..sep.."%dm"..sep.."%." .. tostring(decimals) .. "fs", h, m, s)
elseif m > 0 then
return string.format("%dm"..sep.."%." .. tostring(decimals) .. "fs", m, s)
else
return string.format("%." .. tostring(decimals) .. "fs", s)
end
end
-- Writes text on OSD and console
function log_info(txt, timeout)
timeout = timeout or 1.5
msg.info(txt)
mp.osd_message(txt, timeout)
end
-- Join table items, ala ({"a", "b", "c"}, "=", "-", ", ") => "=a-, =b-, =c-"
function join_table(source, before, after, sep)
before = before or ""
after = after or ""
sep = sep or ", "
local result = ""
for i, v in pairs(source) do
if not isempty(v) then
local part = before .. v .. after
if i == 1 then
result = part
else
result = result .. sep .. part
end
end
end
return result
end
function wrap(s, char)
char = char or "'"
return char .. s .. char
end
-- Wraps given string into 'string' and escapes any 's in it
function escape_and_wrap(s, char, replacement)
char = char or "'"
replacement = replacement or "\\" .. char
return wrap(string.gsub(s, char, replacement), char)
end
-- Escapes single quotes in a string and wraps the input in single quotes
function escape_single_bash(s)
return escape_and_wrap(s, "'", "'\\''")
end
-- Returns (a .. b) if b is not empty or nil
function joined_or_nil(a, b)
return not isempty(b) and (a .. b) or nil
end
-- Put items from one table into another
function extend_table(target, source)
for i, v in pairs(source) do
table.insert(target, v)
end
end
-- Creates a handle and filename for a temporary random file (in current directory)
function create_temporary_file(base, mode, suffix)
local handle, filename
suffix = suffix or ""
while true do
filename = base .. tostring(math.random(1, 5000)) .. suffix
handle = io.open(filename, "r")
if not handle then
handle = io.open(filename, mode)
break
end
io.close(handle)
end
return handle, filename
end
function get_processor_count()
local proc_count
if ON_WINDOWS then
proc_count = tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
else
local cpuinfo_handle = io.open("/proc/cpuinfo")
if cpuinfo_handle ~= nil then
local cpuinfo_contents = cpuinfo_handle:read("*a")
local _, replace_count = cpuinfo_contents:gsub('processor', '')
proc_count = replace_count
end
end
if proc_count and proc_count > 0 then
return proc_count
else
return nil
end
end
function substitute_values(string, values)
local substitutor = function(match)
if match == "%" then
return "%"
else
-- nil is discarded by gsub
return values[match]
end
end
local substituted = string:gsub('%%(.)', substitutor)
return substituted
end
-- ASS HELPERS --
function round_rect_top( ass, x0, y0, x1, y1, r )
local c = 0.551915024494 * r -- circle approximation
ass:move_to(x0 + r, y0)
ass:line_to(x1 - r, y0) -- top line
if r > 0 then
ass:bezier_curve(x1 - r + c, y0, x1, y0 + r - c, x1, y0 + r) -- top right corner
end
ass:line_to(x1, y1) -- right line
ass:line_to(x0, y1) -- bottom line
ass:line_to(x0, y0 + r) -- left line
if r > 0 then
ass:bezier_curve(x0, y0 + r - c, x0 + r - c, y0, x0 + r, y0) -- top left corner
end
end
function round_rect(ass, x0, y0, x1, y1, rtl, rtr, rbr, rbl)
local c = 0.551915024494
ass:move_to(x0 + rtl, y0)
ass:line_to(x1 - rtr, y0) -- top line
if rtr > 0 then
ass:bezier_curve(x1 - rtr + rtr*c, y0, x1, y0 + rtr - rtr*c, x1, y0 + rtr) -- top right corner
end
ass:line_to(x1, y1 - rbr) -- right line
if rbr > 0 then
ass:bezier_curve(x1, y1 - rbr + rbr*c, x1 - rbr + rbr*c, y1, x1 - rbr, y1) -- bottom right corner
end
ass:line_to(x0 + rbl, y1) -- bottom line
if rbl > 0 then
ass:bezier_curve(x0 + rbl - rbl*c, y1, x0, y1 - rbl + rbl*c, x0, y1 - rbl) -- bottom left corner
end
ass:line_to(x0, y0 + rtl) -- left line
if rtl > 0 then
ass:bezier_curve(x0, y0 + rtl - rtl*c, x0 + rtl - rtl*c, y0, x0 + rtl, y0) -- top left corner
end
end
local SCRIPT_NAME = "mpv_thumbnail_script"
local default_cache_base = ON_WINDOWS and os.getenv("TEMP") or "/tmp/"
local thumbnailer_options = {
-- The thumbnail directory
cache_directory = join_paths(default_cache_base, "mpv_thumbs_cache"),
------------------------
-- Generation options --
------------------------
-- Automatically generate the thumbnails on video load, without a keypress
autogenerate = true,
-- Only automatically thumbnail videos shorter than this (seconds)
autogenerate_max_duration = 3600, -- 1 hour
-- SHA1-sum filenames over this length
-- It's nice to know what files the thumbnails are (hence directory names)
-- but long URLs may approach filesystem limits.
hash_filename_length = 128,
-- Use mpv to generate thumbnail even if ffmpeg is found in PATH
-- ffmpeg does not handle ordered chapters (MKVs which rely on other MKVs)!
-- mpv is a bit slower, but has better support overall (eg. subtitles in the previews)
prefer_mpv = true,
-- Explicitly disable subtitles on the mpv sub-calls
mpv_no_sub = false,
-- Add a "--no-config" to the mpv sub-call arguments
mpv_no_config = false,
-- Add a "--profile=<mpv_profile>" to the mpv sub-call arguments
-- Use "" to disable
mpv_profile = "",
-- Output debug logs to <thumbnail_path>.log, ala <cache_directory>/<video_filename>/000000.bgra.log
-- The logs are removed after successful encodes, unless you set mpv_keep_logs below
mpv_logs = true,
-- Keep all mpv logs, even the succesfull ones
mpv_keep_logs = false,
-- Disable the built-in keybind ("T") to add your own
disable_keybinds = false,
---------------------
-- Display options --
---------------------
-- Move the thumbnail up or down
-- For example:
-- topbar/bottombar: 24
-- rest: 0
vertical_offset = 24,
-- Adjust background padding
-- Examples:
-- topbar: 0, 10, 10, 10
-- bottombar: 10, 0, 10, 10
-- slimbox/box: 10, 10, 10, 10
pad_top = 10,
pad_bot = 0,
pad_left = 10,
pad_right = 10,
-- If true, pad values are screen-pixels. If false, video-pixels.
pad_in_screenspace = true,
-- Calculate pad into the offset
offset_by_pad = true,
-- Background color in BBGGRR
background_color = "000000",
-- Alpha: 0 - fully opaque, 255 - transparent
background_alpha = 80,
-- Keep thumbnail on the screen near left or right side
constrain_to_screen = true,
-- Do not display the thumbnailing progress
hide_progress = false,
-----------------------
-- Thumbnail options --
-----------------------
-- The maximum dimensions of the thumbnails (pixels)
thumbnail_width = 200,
thumbnail_height = 200,
-- The thumbnail count target
-- (This will result in a thumbnail every ~10 seconds for a 25 minute video)
thumbnail_count = 150,
-- The above target count will be adjusted by the minimum and
-- maximum time difference between thumbnails.
-- The thumbnail_count will be used to calculate a target separation,
-- and min/max_delta will be used to constrict it.
-- In other words, thumbnails will be:
-- at least min_delta seconds apart (limiting the amount)
-- at most max_delta seconds apart (raising the amount if needed)
min_delta = 5,
-- 120 seconds aka 2 minutes will add more thumbnails when the video is over 5 hours!
max_delta = 90,
-- Overrides for remote urls (you generally want less thumbnails!)
-- Thumbnailing network paths will be done with mpv
-- Allow thumbnailing network paths (naive check for "://")
thumbnail_network = false,
-- Override thumbnail count, min/max delta
remote_thumbnail_count = 60,
remote_min_delta = 15,
remote_max_delta = 120,
-- Try to grab the raw stream and disable ytdl for the mpv subcalls
-- Much faster than passing the url to ytdl again, but may cause problems with some sites
remote_direct_stream = true,
}
read_options(thumbnailer_options, SCRIPT_NAME)
function skip_nil(tbl)
local n = {}
for k, v in pairs(tbl) do
table.insert(n, v)
end
return n
end
function create_thumbnail_mpv(file_path, timestamp, size, output_path, options)
options = options or {}
local ytdl_disabled = not options.enable_ytdl and (mp.get_property_native("ytdl") == false
or thumbnailer_options.remote_direct_stream)
local header_fields_arg = nil
local header_fields = mp.get_property_native("http-header-fields")
if #header_fields > 0 then
-- We can't escape the headers, mpv won't parse "--http-header-fields='Name: value'" properly
header_fields_arg = "--http-header-fields=" .. table.concat(header_fields, ",")
end
local profile_arg = nil
if thumbnailer_options.mpv_profile ~= "" then
profile_arg = "--profile=" .. thumbnailer_options.mpv_profile
end
local log_arg = "--log-file=" .. output_path .. ".log"
local mpv_command = skip_nil({
"mpv",
-- Hide console output
"--msg-level=all=no",
-- Disable ytdl
(ytdl_disabled and "--no-ytdl" or nil),
-- Pass HTTP headers from current instance
header_fields_arg,
-- Pass User-Agent and Referer - should do no harm even with ytdl active
"--user-agent=" .. mp.get_property_native("user-agent"),
"--referrer=" .. mp.get_property_native("referrer"),
-- Disable hardware decoding
"--hwdec=no",
-- Insert --no-config, --profile=... and --log-file if enabled
(thumbnailer_options.mpv_no_config and "--no-config" or nil),
profile_arg,
(thumbnailer_options.mpv_logs and log_arg or nil),
file_path,
"--start=" .. tostring(timestamp),
"--frames=1",
"--hr-seek=yes",
"--no-audio",
-- Optionally disable subtitles
(thumbnailer_options.mpv_no_sub and "--no-sub" or nil),
("--vf=scale=%d:%d"):format(size.w, size.h),
"--vf-add=format=bgra",
"--of=rawvideo",
"--ovc=rawvideo",
"--o=" .. output_path
})
return utils.subprocess({args=mpv_command})
end
function create_thumbnail_ffmpeg(file_path, timestamp, size, output_path)
local ffmpeg_command = {
"ffmpeg",
"-loglevel", "quiet",
"-noaccurate_seek",
"-ss", format_time(timestamp, ":"),
"-i", file_path,
"-frames:v", "1",
"-an",
"-vf", ("scale=%d:%d"):format(size.w, size.h),
"-c:v", "rawvideo",
"-pix_fmt", "bgra",
"-f", "rawvideo",
"-y", output_path
}
return utils.subprocess({args=ffmpeg_command})
end
function check_output(ret, output_path, is_mpv)
local log_path = output_path .. ".log"
local success = true
if ret.killed_by_us then
return nil
else
if ret.error or ret.status ~= 0 then
msg.error("Thumbnailing command failed!")
msg.error("mpv process error:", ret.error)
msg.error("Process stdout:", ret.stdout)
if is_mpv then
msg.error("Debug log:", log_path)
end
success = false
end
if not file_exists(output_path) then
msg.error("Output file missing!", output_path)
success = false
end
end
if is_mpv and not thumbnailer_options.mpv_keep_logs then
-- Remove successful debug logs
if success and file_exists(log_path) then
os.remove(log_path)
end
end
return success
end
function do_worker_job(state_json_string, frames_json_string)
msg.debug("Handling given job")
local thumb_state, err = utils.parse_json(state_json_string)
if err then
msg.error("Failed to parse state JSON")
return
end
local thumbnail_indexes, err = utils.parse_json(frames_json_string)
if err then
msg.error("Failed to parse thumbnail frame indexes")
return
end
local thumbnail_func = create_thumbnail_mpv
if not thumbnailer_options.prefer_mpv then
if ExecutableFinder:get_executable_path("ffmpeg") then
thumbnail_func = create_thumbnail_ffmpeg
else
msg.warn("Could not find ffmpeg in PATH! Falling back on mpv.")
end
end
local file_duration = mp.get_property_native("duration")
local file_path = thumb_state.worker_input_path
if thumb_state.is_remote then
if (thumbnail_func == create_thumbnail_ffmpeg) then
msg.warn("Thumbnailing remote path, falling back on mpv.")
end
thumbnail_func = create_thumbnail_mpv
end
local generate_thumbnail_for_index = function(thumbnail_index)
-- Given a 1-based thumbnail index, generate a thumbnail for it based on the thumbnailer state
local thumb_idx = thumbnail_index - 1
msg.debug("Starting work on thumbnail", thumb_idx)
local thumbnail_path = thumb_state.thumbnail_template:format(thumb_idx)
-- Grab the "middle" of the thumbnail duration instead of the very start, and leave some margin in the end
local timestamp = math.min(file_duration - 0.25, (thumb_idx + 0.5) * thumb_state.thumbnail_delta)
mp.commandv("script-message", "mpv_thumbnail_script-progress", tostring(thumbnail_index))
-- The expected size (raw BGRA image)
local thumbnail_raw_size = (thumb_state.thumbnail_size.w * thumb_state.thumbnail_size.h * 4)
local need_thumbnail_generation = false
-- Check if the thumbnail already exists and is the correct size
local thumbnail_file = io.open(thumbnail_path, "rb")
if thumbnail_file == nil then
need_thumbnail_generation = true
else
local existing_thumbnail_filesize = thumbnail_file:seek("end")
if existing_thumbnail_filesize ~= thumbnail_raw_size then
-- Size doesn't match, so (re)generate
msg.warn("Thumbnail", thumb_idx, "did not match expected size, regenerating")
need_thumbnail_generation = true
end
thumbnail_file:close()
end
if need_thumbnail_generation then
local ret = thumbnail_func(file_path, timestamp, thumb_state.thumbnail_size, thumbnail_path, thumb_state.worker_extra)
local success = check_output(ret, thumbnail_path, thumbnail_func == create_thumbnail_mpv)
if success == nil then
-- Killed by us, changing files, ignore
msg.debug("Changing files, subprocess killed")
return true
elseif not success then
-- Real failure
mp.osd_message("Thumbnailing failed, check console for details", 3.5)
return true
end
else
msg.debug("Thumbnail", thumb_idx, "already done!")
end
-- Verify thumbnail size
-- Sometimes ffmpeg will output an empty file when seeking to a "bad" section (usually the end)
thumbnail_file = io.open(thumbnail_path, "rb")
-- Bail if we can't read the file (it should really exist by now, we checked this in check_output!)
if thumbnail_file == nil then
msg.error("Thumbnail suddenly disappeared!")
return true
end
-- Check the size of the generated file
local thumbnail_file_size = thumbnail_file:seek("end")
thumbnail_file:close()
-- Check if the file is big enough
local missing_bytes = math.max(0, thumbnail_raw_size - thumbnail_file_size)
if missing_bytes > 0 then
msg.warn(("Thumbnail missing %d bytes (expected %d, had %d), padding %s"):format(
missing_bytes, thumbnail_raw_size, thumbnail_file_size, thumbnail_path
))
-- Pad the file if it's missing content (eg. ffmpeg seek to file end)
thumbnail_file = io.open(thumbnail_path, "ab")
thumbnail_file:write(string.rep(string.char(0), missing_bytes))
thumbnail_file:close()
end
msg.debug("Finished work on thumbnail", thumb_idx)
mp.commandv("script-message", "mpv_thumbnail_script-ready", tostring(thumbnail_index), thumbnail_path)
end
msg.debug(("Generating %d thumbnails @ %dx%d for %q"):format(
#thumbnail_indexes,
thumb_state.thumbnail_size.w,
thumb_state.thumbnail_size.h,
file_path))
for i, thumbnail_index in ipairs(thumbnail_indexes) do
local bail = generate_thumbnail_for_index(thumbnail_index)
if bail then return end
end
end
-- Set up listeners and keybinds
-- Job listener
mp.register_script_message("mpv_thumbnail_script-job", do_worker_job)
-- Register this worker with the master script
local register_timer = nil
local register_timeout = mp.get_time() + 1.5
local register_function = function()
if mp.get_time() > register_timeout and register_timer then
msg.error("Thumbnail worker registering timed out")
register_timer:stop()
else
msg.debug("Announcing self to master...")
mp.commandv("script-message", "mpv_thumbnail_script-worker", mp.get_script_name())
end
end
register_timer = mp.add_periodic_timer(0.1, register_function)
mp.register_script_message("mpv_thumbnail_script-slaved", function()
msg.debug("Successfully registered with master")
register_timer:stop()
end)

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,7 @@
local settings = { local settings = {
-- #### FUNCTIONALITY SETTINGS
--navigation keybindings force override only while playlist is visible --navigation keybindings force override only while playlist is visible
--if "no" then you can display the playlist by any of the navigation keys --if "no" then you can display the playlist by any of the navigation keys
dynamic_binds = true, dynamic_binds = true,
@@ -111,12 +114,11 @@ local settings = {
save_playlist_on_file_end = false, save_playlist_on_file_end = false,
--show file title every time a new file is loaded --show playlist or filename every time a new file is loaded
show_title_on_file_load = false, --2 shows playlist, 1 shows current file(filename strip applied) as osd text, 0 shows nothing
--show playlist every time a new file is loaded --instead of using this you can also call script-message playlistmanager show playlist/filename
show_playlist_on_file_load = false, --ex. KEY playlist-next ; script-message playlistmanager show playlist
--close playlist when selecting file to play show_playlist_on_fileload = 0,
close_playlist_on_playfile = false,
--sync cursor when file is loaded from outside reasons(file-ending, playlist-next shortcut etc.) --sync cursor when file is loaded from outside reasons(file-ending, playlist-next shortcut etc.)
--has the sideeffect of moving cursor if file happens to change when navigating --has the sideeffect of moving cursor if file happens to change when navigating
@@ -126,6 +128,8 @@ local settings = {
--allow the playlist cursor to loop from end to start and vice versa --allow the playlist cursor to loop from end to start and vice versa
loop_cursor = true, loop_cursor = true,
--youtube-dl executable for title resolving if enabled, probably "youtube-dl" or "yt-dlp", can be absolute path
youtube_dl_executable = "youtube-dl",
-- allow playlistmanager to write watch later config when navigating between files -- allow playlistmanager to write watch later config when navigating between files
allow_write_watch_later_config = true, allow_write_watch_later_config = true,
@@ -134,12 +138,11 @@ local settings = {
reset_cursor_on_close = true, reset_cursor_on_close = true,
reset_cursor_on_open = true, reset_cursor_on_open = true,
--#### VISUAL SETTINGS
--prefer to display titles for following files: "all", "url", "none". Sorting still uses filename. --prefer to display titles for following files: "all", "url", "none". Sorting still uses filename.
prefer_titles = "url", prefer_titles = "url",
--youtube-dl executable for title resolving if enabled, probably "youtube-dl" or "yt-dlp", can be absolute path
youtube_dl_executable = "yt-dlp",
--call youtube-dl to resolve the titles of urls in the playlist --call youtube-dl to resolve the titles of urls in the playlist
resolve_url_titles = false, resolve_url_titles = false,
@@ -158,23 +161,23 @@ local settings = {
-- when peeking at playlist, show playlist at the very least for display timeout -- when peeking at playlist, show playlist at the very least for display timeout
peek_respect_display_timeout = false, peek_respect_display_timeout = false,
-- the maximum amount of lines playlist will render. -1 will automatically calculate lines. -- the maximum amount of lines playlist will render. Optimal value depends on font/video size etc.
showamount = -1, showamount = 9,
--font size scales by window, if false requires larger font and padding sizes
scale_playlist_by_window=true,
--playlist ass style overrides inside curly brackets, \keyvalue is one field, extra \ for escape in lua --playlist ass style overrides inside curly brackets, \keyvalue is one field, extra \ for escape in lua
--example {\\q2\\an7\\fnUbuntu\\fs10\\b0\\bord1} equals: line-wrap=no, align=top left, font=Ubuntu, size=10, bold=no, border=1 --example {\\fnUbuntu\\fs10\\b0\\bord1} equals: font=Ubuntu, size=10, bold=no, border=1
--read http://docs.aegisub.org/3.2/ASS_Tags/ for reference of tags --read http://docs.aegisub.org/3.2/ASS_Tags/ for reference of tags
--undeclared tags will use default osd settings --undeclared tags will use default osd settings
--these styles will be used for the whole playlist --these styles will be used for the whole playlist
--\\q2 style is recommended since filename wrapping may lead to unexpected rendering style_ass_tags = "{}",
--\\an7 style is recommended to align to top left otherwise, osd-align-x/y is respected --paddings from top left corner
style_ass_tags = "{\\q2\\an7}", text_padding_x = 10,
--paddings for left right and top bottom text_padding_y = 30,
text_padding_x = 30,
text_padding_y = 60,
--screen dim when menu is open 0.0 - 1.0 (0 is no dim, 1 is black) --screen dim when menu is open 0.0 - 1.0 (0 is no dim, 1 is black)
curtain_opacity=0.0, curtain_opacity=0,
--set title of window with stripped name --set title of window with stripped name
set_title_stripped = false, set_title_stripped = false,
@@ -222,17 +225,6 @@ local utils = require("mp.utils")
local msg = require("mp.msg") local msg = require("mp.msg")
local assdraw = require("mp.assdraw") local assdraw = require("mp.assdraw")
local alignment_table = {
[1] = { ["x"] = "left", ["y"] = "bottom" },
[2] = { ["x"] = "center", ["y"] = "bottom" },
[3] = { ["x"] = "right", ["y"] = "bottom" },
[4] = { ["x"] = "left", ["y"] = "center" },
[5] = { ["x"] = "center", ["y"] = "center" },
[6] = { ["x"] = "right", ["y"] = "center" },
[7] = { ["x"] = "left", ["y"] = "top" },
[8] = { ["x"] = "center", ["y"] = "top" },
[9] = { ["x"] = "right", ["y"] = "top" },
}
--check os --check os
if settings.system=="auto" then if settings.system=="auto" then
@@ -244,47 +236,7 @@ if settings.system=="auto" then
end end
end end
-- auto calculate showamount
if settings.showamount == -1 then
-- same as draw_playlist() height
local h = 720
local playlist_h = h
-- both top and bottom with same padding
playlist_h = playlist_h - settings.text_padding_y * 2
-- osd-font-size is based on 720p height
-- see https://mpv.io/manual/stable/#options-osd-font-size
-- details in https://mpv.io/manual/stable/#options-sub-font-size
-- draw_playlist() is based on 720p, need some conversion
local fs = mp.get_property_native('osd-font-size') * h / 720
-- get the ass font size
if settings.style_ass_tags ~= nil then
local ass_fs_tag = settings.style_ass_tags:match('\\fs%d+')
if ass_fs_tag ~= nil then
fs = tonumber(ass_fs_tag:match('%d+'))
end
end
settings.showamount = math.floor(playlist_h / fs)
-- exclude the header line
if settings.playlist_header ~= "" then
settings.showamount = settings.showamount - 1
-- probably some newlines (%N or \N) in the header
for _ in settings.playlist_header:gmatch('%%N') do
settings.showamount = settings.showamount - 1
end
for _ in settings.playlist_header:gmatch('\\N') do
settings.showamount = settings.showamount - 1
end
end
msg.info('auto showamount: ' .. settings.showamount)
end
--global variables --global variables
local playlist_overlay = mp.create_osd_overlay("ass-events")
local playlist_visible = false local playlist_visible = false
local strippedname = nil local strippedname = nil
local path = nil local path = nil
@@ -300,13 +252,6 @@ local requested_titles = {}
local filetype_lookup = {} local filetype_lookup = {}
function refresh_UI()
if not playlist_visible then return end
refresh_globals()
if plen == 0 then return end
draw_playlist()
end
function update_opts(changelog) function update_opts(changelog)
msg.verbose('updating options') msg.verbose('updating options')
@@ -343,56 +288,16 @@ function update_opts(changelog)
keybindstimer:kill() keybindstimer:kill()
end end
refresh_UI() if playlist_visible then showplaylist() end
end end
update_opts({filename_replace = true, loadfiles_filetypes = true}) update_opts({filename_replace = true, loadfiles_filetypes = true})
----- winapi start -----
-- in windows system, we can use the sorting function provided by the win32 API
-- see https://learn.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-strcmplogicalw
local winapisort = nil
if settings.system == "windows" then
-- ffiok is false usually means the mpv builds without luajit
local ffiok, ffi = pcall(require, "ffi")
if ffiok then
ffi.cdef[[
int MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
int StrCmpLogicalW(const wchar_t * psz1, const wchar_t * psz2);
]]
local shlwapi = ffi.load("shlwapi.dll")
function MultiByteToWideChar(MultiByteStr)
local UTF8_CODEPAGE = 65001
if MultiByteStr then
local utf16_len = ffi.C.MultiByteToWideChar(UTF8_CODEPAGE, 0, MultiByteStr, -1, nil, 0)
if utf16_len > 0 then
local utf16_str = ffi.new("wchar_t[?]", utf16_len)
if ffi.C.MultiByteToWideChar(UTF8_CODEPAGE, 0, MultiByteStr, -1, utf16_str, utf16_len) > 0 then
return utf16_str
end
end
end
return ""
end
winapisort = function (a, b)
return shlwapi.StrCmpLogicalW(MultiByteToWideChar(a), MultiByteToWideChar(b)) < 0
end
end
end
----- winapi end -----
local sort_modes = { local sort_modes = {
{ {
id="name-asc", id="name-asc",
title="name ascending", title="name ascending",
sort_fn=function (a, b, playlist) sort_fn=function (a, b, playlist)
if winapisort ~= nil then
return winapisort(playlist[a].string, playlist[b].string)
end
return alphanumsort(playlist[a].string, playlist[b].string) return alphanumsort(playlist[a].string, playlist[b].string)
end, end,
}, },
@@ -400,9 +305,6 @@ local sort_modes = {
id="name-desc", id="name-desc",
title="name descending", title="name descending",
sort_fn=function (a, b, playlist) sort_fn=function (a, b, playlist)
if winapisort ~= nil then
return winapisort(playlist[b].string, playlist[a].string)
end
return alphanumsort(playlist[b].string, playlist[a].string) return alphanumsort(playlist[b].string, playlist[a].string)
end, end,
}, },
@@ -449,9 +351,6 @@ end
function on_file_loaded() function on_file_loaded()
refresh_globals() refresh_globals()
if settings.sync_cursor_on_load then cursor=pos end
refresh_UI() -- refresh only after moving cursor
filename = mp.get_property("filename") filename = mp.get_property("filename")
path = mp.get_property('path') path = mp.get_property('path')
local media_title = mp.get_property("media-title") local media_title = mp.get_property("media-title")
@@ -459,12 +358,17 @@ function on_file_loaded()
title_table[path] = media_title title_table[path] = media_title
end end
strippedname = stripfilename(mp.get_property('media-title')) if settings.sync_cursor_on_load then
if settings.show_title_on_file_load then cursor=pos
mp.commandv('show-text', strippedname) --refresh playlist if cursor moved
if playlist_visible then draw_playlist() end
end end
if settings.show_playlist_on_file_load then
strippedname = stripfilename(mp.get_property('media-title'))
if settings.show_playlist_on_fileload == 2 then
showplaylist() showplaylist()
elseif settings.show_playlist_on_fileload == 1 then
mp.commandv('show-text', strippedname)
end end
if settings.set_title_stripped then if settings.set_title_stripped then
mp.set_property("title", settings.title_prefix..strippedname..settings.title_suffix) mp.set_property("title", settings.title_prefix..strippedname..settings.title_suffix)
@@ -499,6 +403,7 @@ function on_end_file()
path = nil path = nil
directory = nil directory = nil
filename = nil filename = nil
if playlist_visible then showplaylist() end
end end
function refresh_globals() function refresh_globals()
@@ -522,28 +427,6 @@ local filename_replace_functions = {
hex_to_char = function(x) return string.char(tonumber(x, 16)) end hex_to_char = function(x) return string.char(tonumber(x, 16)) end
} }
-- from http://lua-users.org/wiki/LuaUnicode
local UTF8_PATTERN = '[%z\1-\127\194-\244][\128-\191]*'
-- return a substring based on utf8 characters
-- like string.sub, but negative index is not supported
local function utf8_sub(s, i, j)
if i > j then
return s
end
local t = {}
local idx = 1
for char in s:gmatch(UTF8_PATTERN) do
if i <= idx and idx <= j then
local width = #char > 2 and 2 or 1
idx = idx + width
t[#t + 1] = char
end
end
return table.concat(t)
end
--strip a filename based on its extension or protocol according to rules in settings --strip a filename based on its extension or protocol according to rules in settings
function stripfilename(pathfile, media_title) function stripfilename(pathfile, media_title)
if pathfile == nil then return '' end if pathfile == nil then return '' end
@@ -563,9 +446,8 @@ function stripfilename(pathfile, media_title)
end end
end end
end end
local tmp_clip = utf8_sub(tmp, 1, settings.slice_longfilenames_amount) if settings.slice_longfilenames and tmp:len()>settings.slice_longfilenames_amount+5 then
if settings.slice_longfilenames and tmp ~= tmp_clip then tmp = tmp:sub(1, settings.slice_longfilenames_amount).." ..."
tmp = tmp_clip .. "..."
end end
return tmp return tmp
end end
@@ -592,10 +474,17 @@ function get_name_from_index(i, notitle)
local name = mp.get_property('playlist/'..i..'/filename') local name = mp.get_property('playlist/'..i..'/filename')
local should_use_title = settings.prefer_titles == 'all' or is_protocol(name) and settings.prefer_titles == 'url' local should_use_title = settings.prefer_titles == 'all' or is_protocol(name) and settings.prefer_titles == 'url'
--check if file has a media title stored or as property
--check if file has a media title stored if not title and should_use_title then
if not title and should_use_title and title_table[name] then local mtitle = mp.get_property('media-title')
title = title_table[name] if i == pos and mp.get_property('filename') ~= mtitle then
if not title_table[name] then
title_table[name] = mtitle
end
title = mtitle
elseif title_table[name] then
title = title_table[name]
end
end end
--if we have media title use a more conservative strip --if we have media title use a more conservative strip
@@ -616,8 +505,6 @@ function parse_header(string)
local esc_title = stripfilename(mp.get_property("media-title"), true):gsub("%%", "%%%%") local esc_title = stripfilename(mp.get_property("media-title"), true):gsub("%%", "%%%%")
local esc_file = stripfilename(mp.get_property("filename")):gsub("%%", "%%%%") local esc_file = stripfilename(mp.get_property("filename")):gsub("%%", "%%%%")
return string:gsub("%%N", "\\N") return string:gsub("%%N", "\\N")
-- add a blank character at the end of each '\N' to ensure that the height of the empty line is the same as the non empty line
:gsub("\\N", "\\N ")
:gsub("%%pos", mp.get_property_number("playlist-pos",0)+1) :gsub("%%pos", mp.get_property_number("playlist-pos",0)+1)
:gsub("%%plen", mp.get_property("playlist-count")) :gsub("%%plen", mp.get_property("playlist-count"))
:gsub("%%cursor", cursor+1) :gsub("%%cursor", cursor+1)
@@ -664,21 +551,16 @@ function parse_filename_by_index(index)
return parse_filename(template, get_name_from_index(index), index) return parse_filename(template, get_name_from_index(index), index)
end end
function is_terminal_mode()
local width, height, aspect_ratio = mp.get_osd_size()
return width == 0 and height == 0 and aspect_ratio == 0
end
function draw_playlist() function draw_playlist()
refresh_globals() refresh_globals()
local ass = assdraw.ass_new() local ass = assdraw.ass_new()
local terminaloutput = ""
local _, _, a = mp.get_osd_size() local _, _, a = mp.get_osd_size()
local h = 720 local h = 360
local w = math.ceil(h * a) local w = h * a
if settings.curtain_opacity ~= nil and settings.curtain_opacity ~= 0 and settings.curtain_opacity <= 1.0 then if settings.curtain_opacity ~= nil and settings.curtain_opacity ~= 0 and settings.curtain_opacity < 1.0 then
-- curtain dim from https://github.com/christoph-heinrich/mpv-quality-menu/blob/501794bfbef468ee6a61e54fc8821fe5cd72c4ed/quality-menu.lua#L699-L707 -- curtain dim from https://github.com/christoph-heinrich/mpv-quality-menu/blob/501794bfbef468ee6a61e54fc8821fe5cd72c4ed/quality-menu.lua#L699-L707
local alpha = 255 - math.ceil(255 * settings.curtain_opacity) local alpha = 255 - math.ceil(255 * settings.curtain_opacity)
ass.text = string.format('{\\pos(0,0)\\rDefault\\an7\\1c&H000000&\\alpha&H%X&}', alpha) ass.text = string.format('{\\pos(0,0)\\rDefault\\an7\\1c&H000000&\\alpha&H%X&}', alpha)
@@ -690,53 +572,13 @@ function draw_playlist()
ass:append(settings.style_ass_tags) ass:append(settings.style_ass_tags)
-- add \clip style -- TODO: padding should work even on different osd alignments
-- make both left and right follow text_padding_x if mp.get_property("osd-align-x") == "left" and mp.get_property("osd-align-y") == "top" then
-- both top and bottom follow text_padding_y ass:pos(settings.text_padding_x, settings.text_padding_y)
local border_size = mp.get_property_number('osd-border-size')
if settings.style_ass_tags ~= nil then
local bord = tonumber(settings.style_ass_tags:match('\\bord(%d+%.?%d*)'))
if bord ~= nil then border_size = bord end
end end
ass:append(string.format('{\\clip(%f,%f,%f,%f)}',
settings.text_padding_x - border_size, settings.text_padding_y - border_size,
w - 1 - settings.text_padding_x + border_size, h - 1 - settings.text_padding_y + border_size))
-- align from mpv.conf
local align_x = mp.get_property("osd-align-x")
local align_y = mp.get_property("osd-align-y")
-- align from style_ass_tags
if settings.style_ass_tags ~= nil then
local an = tonumber(settings.style_ass_tags:match('\\an(%d)'))
if an ~= nil and alignment_table[an] ~= nil then
align_x = alignment_table[an]["x"]
align_y = alignment_table[an]["y"]
end
end
-- range of x [0, w-1]
local pos_x
if align_x == 'left' then
pos_x = settings.text_padding_x
elseif align_x == 'right' then
pos_x = w - 1 - settings.text_padding_x
else
pos_x = math.floor((w - 1) / 2)
end
-- range of y [0, h-1]
local pos_y
if align_y == 'top' then
pos_y = settings.text_padding_y
elseif align_y == 'bottom' then
pos_y = h - 1 - settings.text_padding_y
else
pos_y = math.floor((h - 1) / 2)
end
ass:pos(pos_x, pos_y)
if settings.playlist_header ~= "" then if settings.playlist_header ~= "" then
local header = parse_header(settings.playlist_header) ass:append(parse_header(settings.playlist_header).."\\N")
ass:append(header.."\\N")
terminaloutput = terminaloutput..header.."\n"
end end
-- (visible index, playlist index) pairs of playlist entries that should be rendered -- (visible index, playlist index) pairs of playlist entries that should be rendered
@@ -770,28 +612,16 @@ function draw_playlist()
for display_index, playlist_index in pairs(visible_indices) do for display_index, playlist_index in pairs(visible_indices) do
if display_index == 1 and playlist_index ~= 1 then if display_index == 1 and playlist_index ~= 1 then
ass:append(settings.playlist_sliced_prefix.."\\N") ass:append(settings.playlist_sliced_prefix.."\\N")
terminaloutput = terminaloutput..settings.playlist_sliced_prefix.."\n"
elseif display_index == settings.showamount and playlist_index ~= plen then elseif display_index == settings.showamount and playlist_index ~= plen then
ass:append(settings.playlist_sliced_suffix) ass:append(settings.playlist_sliced_suffix)
terminaloutput = terminaloutput..settings.playlist_sliced_suffix.."\n"
else else
-- parse_filename_by_index expects 0 based index -- parse_filename_by_index expects 0 based index
local fname = parse_filename_by_index(playlist_index - 1) ass:append(parse_filename_by_index(playlist_index - 1).."\\N")
ass:append(fname.."\\N")
terminaloutput = terminaloutput..fname.."\n"
end end
end end
if is_terminal_mode() then if settings.scale_playlist_by_window then w,h = 0, 0 end
local timeout_setting = settings.playlist_display_timeout mp.set_osd_ass(w, h, ass.text)
local timeout = timeout_setting == 0 and 2147483 or timeout_setting
-- TODO: probably have to strip ass tags from terminal output
-- would maybe be possible to use terminal color output instead
mp.osd_message(terminaloutput, timeout)
else
playlist_overlay.data = ass.text
playlist_overlay:update()
end
end end
local peek_display_timer = nil local peek_display_timer = nil
@@ -863,7 +693,7 @@ function showplaylist(duration)
draw_playlist() draw_playlist()
keybindstimer:kill() keybindstimer:kill()
local dur = tonumber(duration) or settings.playlist_display_timeout local dur = duration or settings.playlist_display_timeout
if dur > 0 then if dur > 0 then
keybindstimer = mp.add_periodic_timer(dur, remove_keybinds) keybindstimer = mp.add_periodic_timer(dur, remove_keybinds)
end end
@@ -879,7 +709,7 @@ function showplaylist_non_interactive(duration)
draw_playlist() draw_playlist()
keybindstimer:kill() keybindstimer:kill()
local dur = tonumber(duration) or settings.playlist_display_timeout local dur = duration or settings.playlist_display_timeout
if dur > 0 then if dur > 0 then
keybindstimer = mp.add_periodic_timer(dur, remove_keybinds) keybindstimer = mp.add_periodic_timer(dur, remove_keybinds)
end end
@@ -947,44 +777,26 @@ function movedown()
showplaylist() showplaylist()
end end
function movepageup() function movepageup()
refresh_globals() refresh_globals()
if plen == 0 or cursor == 0 then return end if plen == 0 or cursor == 0 then return end
local offset = settings.showamount % 2 == 0 and 1 or 0
local last_file_that_doesnt_scroll = math.ceil(settings.showamount / 2)
local reverse_cursor = plen - cursor
local files_to_jump = math.max(last_file_that_doesnt_scroll + offset - reverse_cursor, 0) + settings.showamount - 2
local prev_cursor = cursor local prev_cursor = cursor
cursor = cursor - files_to_jump cursor = cursor - settings.showamount
if cursor < last_file_that_doesnt_scroll then if cursor < 0 then cursor = 0 end
cursor = 0 if selection then mp.commandv("playlist-move", prev_cursor, cursor) end
end
if selection then
mp.commandv("playlist-move", prev_cursor, cursor)
end
showplaylist() showplaylist()
end end
function movepagedown() function movepagedown()
refresh_globals() refresh_globals()
if plen == 0 or cursor == plen - 1 then return end if plen == 0 or cursor == plen-1 then return end
local last_file_that_doesnt_scroll = math.ceil(settings.showamount / 2) - 1
local files_to_jump = math.max(last_file_that_doesnt_scroll - cursor, 0) + settings.showamount - 2
local prev_cursor = cursor local prev_cursor = cursor
cursor = cursor + files_to_jump cursor = cursor + settings.showamount
if cursor >= plen then cursor = plen-1 end
local cursor_on_last_page = plen - (settings.showamount - 3) if selection then mp.commandv("playlist-move", prev_cursor, cursor+1) end
if cursor > cursor_on_last_page then
cursor = plen - 1
end
if selection then
mp.commandv("playlist-move", prev_cursor, cursor + 1)
end
showplaylist() showplaylist()
end end
function movebegin() function movebegin()
refresh_globals() refresh_globals()
if plen == 0 or cursor == 0 then return end if plen == 0 or cursor == 0 then return end
@@ -1011,37 +823,14 @@ function write_watch_later(force_write)
end end
end end
function playlist_next() function playlist_next(force_write)
write_watch_later(true) write_watch_later(force_write)
mp.commandv("playlist-next", "weak") mp.commandv("playlist-next", "weak")
if settings.close_playlist_on_playfile then
remove_keybinds()
end
refresh_UI()
end end
function playlist_prev() function playlist_prev(force_write)
write_watch_later(true) write_watch_later(force_write)
mp.commandv("playlist-prev", "weak") mp.commandv("playlist-prev", "weak")
if settings.close_playlist_on_playfile then
remove_keybinds()
end
refresh_UI()
end
function playlist_random()
write_watch_later()
refresh_globals()
if plen < 2 then return end
math.randomseed(os.time())
local random = pos
while random == pos do
random = math.random(0, plen-1)
end
mp.set_property("playlist-pos", random)
if settings.close_playlist_on_playfile then
remove_keybinds()
end
end end
function playfile() function playfile()
@@ -1059,10 +848,8 @@ function playfile()
write_watch_later() write_watch_later()
mp.commandv("playlist-next", "weak") mp.commandv("playlist-next", "weak")
end end
if settings.close_playlist_on_playfile then if settings.show_playlist_on_fileload ~= 2 then
remove_keybinds() remove_keybinds()
elseif playlist_visible then
showplaylist()
end end
end end
@@ -1105,12 +892,7 @@ function playlist(force_dir)
if force_dir then dir = force_dir end if force_dir then dir = force_dir end
local files = file_filter(utils.readdir(dir, "files")) local files = file_filter(utils.readdir(dir, "files"))
if winapisort ~= nil then table.sort(files, alphanumsort)
table.sort(files, winapisort)
else
table.sort(files, alphanumsort)
end
if files == nil then if files == nil then
msg.verbose("no files in directory") msg.verbose("no files in directory")
@@ -1159,8 +941,7 @@ function playlist(force_dir)
refresh_globals() refresh_globals()
if playlist_visible then if playlist_visible then
showplaylist() showplaylist()
end elseif settings.display_osd_feedback then
if settings.display_osd_feedback then
if c2 > 0 or c>0 then if c2 > 0 or c>0 then
mp.osd_message("Added "..c + c2.." files to playlist") mp.osd_message("Added "..c + c2.." files to playlist")
else else
@@ -1334,8 +1115,7 @@ function reverseplaylist()
end end
if playlist_visible then if playlist_visible then
showplaylist() showplaylist()
end elseif settings.display_osd_feedback then
if settings.display_osd_feedback then
mp.osd_message("Playlist reversed") mp.osd_message("Playlist reversed")
end end
end end
@@ -1361,8 +1141,7 @@ function shuffleplaylist()
refresh_globals() refresh_globals()
if playlist_visible then if playlist_visible then
showplaylist() showplaylist()
end elseif settings.display_osd_feedback then
if settings.display_osd_feedback then
mp.osd_message("Playlist shuffled") mp.osd_message("Playlist shuffled")
end end
end end
@@ -1424,11 +1203,7 @@ function remove_keybinds()
keybindstimer:kill() keybindstimer:kill()
keybindstimer = mp.add_periodic_timer(settings.playlist_display_timeout, remove_keybinds) keybindstimer = mp.add_periodic_timer(settings.playlist_display_timeout, remove_keybinds)
keybindstimer:kill() keybindstimer:kill()
playlist_overlay.data = "" mp.set_osd_ass(0, 0, "")
playlist_overlay:remove()
if is_terminal_mode() then
mp.osd_message("")
end
playlist_visible = false playlist_visible = false
if settings.reset_cursor_on_close then if settings.reset_cursor_on_close then
resetcursor() resetcursor()
@@ -1466,10 +1241,9 @@ mp.observe_property('playlist-count', "number", function(_, plcount)
refresh_globals() refresh_globals()
sortplaylist() sortplaylist()
end end
refresh_UI() if playlist_visible then showplaylist() end
resolve_titles() resolve_titles()
end) end)
mp.observe_property('osd-dimensions', 'native', refresh_UI)
url_request_queue = {} url_request_queue = {}
@@ -1540,10 +1314,10 @@ function resolve_titles()
and not requested_titles[filename] and not requested_titles[filename]
then then
requested_titles[filename] = true requested_titles[filename] = true
if filename:match('^https?://') and settings.resolve_url_titles then if filename:match('^https?://') then
url_titles_to_fetch.push(filename) url_titles_to_fetch.push(filename)
added_urls = true added_urls = true
elseif settings.prefer_titles == "all" and settings.resolve_local_titles then elseif settings.prefer_titles == "all" then
local_titles_to_fetch.push(filename) local_titles_to_fetch.push(filename)
added_local = true added_local = true
end end
@@ -1586,8 +1360,8 @@ function resolve_ytdl_title(filename)
local title = (is_playlist and '[playlist]: ' or '') .. json['title'] local title = (is_playlist and '[playlist]: ' or '') .. json['title']
msg.verbose(filename .. " resolved to '" .. title .. "'") msg.verbose(filename .. " resolved to '" .. title .. "'")
title_table[filename] = title title_table[filename] = title
mp.set_property_native('user-data/playlistmanager/titles', title_table) refresh_globals()
refresh_UI() if playlist_visible then showplaylist() end
else else
msg.error("Failed parsing json, reason: "..(err or "unknown")) msg.error("Failed parsing json, reason: "..(err or "unknown"))
end end
@@ -1627,8 +1401,8 @@ function resolve_ffprobe_title(filename)
if title then if title then
msg.verbose(filename .. " resolved to '" .. title .. "'") msg.verbose(filename .. " resolved to '" .. title .. "'")
title_table[filename] = title title_table[filename] = title
mp.set_property_native('user-data/playlistmanager/titles', title_table) refresh_globals()
refresh_UI() if playlist_visible then showplaylist() end
end end
else else
msg.error("Failed to resolve local title "..filename.." Error: "..(res.error or "unknown")) msg.error("Failed to resolve local title "..filename.." Error: "..(res.error or "unknown"))
@@ -1668,9 +1442,8 @@ function handlemessage(msg, value, value2)
if msg == "reverse" then reverseplaylist() ; return end if msg == "reverse" then reverseplaylist() ; return end
if msg == "loadfiles" then playlist(value) ; return end if msg == "loadfiles" then playlist(value) ; return end
if msg == "save" then save_playlist(value) ; return end if msg == "save" then save_playlist(value) ; return end
if msg == "playlist-next" then playlist_next() ; return end if msg == "playlist-next" then playlist_next(true) ; return end
if msg == "playlist-prev" then playlist_prev() ; return end if msg == "playlist-prev" then playlist_prev(true) ; return end
if msg == "playlist-next-random" then playlist_random() ; return end
if msg == "enable-interactive-save" then interactive_save = true end if msg == "enable-interactive-save" then interactive_save = true end
if msg == "close" then remove_keybinds() end if msg == "close" then remove_keybinds() end
end end

192
mpv/scripts/seek-to.lua Normal file
View File

@@ -0,0 +1,192 @@
-- Original script from https://github.com/occivink/mpv-scripts/blob/master/scripts/seek-to.lua
-- prerequisite: xclip (clipboard CLI interface) installed
local assdraw = require 'mp.assdraw'
local utils = require 'mp.utils'
local msg = require 'mp.msg'
local active = false
local cursor_position = 1
local time_scale = {60*60*10, 60*60, 60*10, 60, 10, 1, 0.1, 0.01, 0.001}
local ass_begin = mp.get_property("osd-ass-cc/0")
local ass_end = mp.get_property("osd-ass-cc/1")
local history = { {} }
for i = 1, 9 do
history[1][i] = 0
end
local history_position = 1
-- timer to redraw periodically the message
-- to avoid leaving bindings when the seeker disappears for whatever reason
-- pretty hacky tbh
local timer = nil
local timer_duration = 3
function show_seeker()
local prepend_char = {'','',':','',':','','.','',''}
local str = ''
for i = 1, 9 do
str = str .. prepend_char[i]
if i == cursor_position then
str = str .. '{\\b1}' .. history[history_position][i] .. '{\\r}'
else
str = str .. history[history_position][i]
end
end
mp.osd_message("Seek to: " .. ass_begin .. str .. ass_end, timer_duration)
end
function copy_history_to_last()
if history_position ~= #history then
for i = 1, 9 do
history[#history][i] = history[history_position][i]
end
history_position = #history
end
end
function change_number(i)
-- can't set above 60 minutes or seconds
if (cursor_position == 3 or cursor_position == 5) and i >= 6 then
return
end
if history[history_position][cursor_position] ~= i then
copy_history_to_last()
history[#history][cursor_position] = i
end
shift_cursor(false)
end
function shift_cursor(left)
if left then
cursor_position = math.max(1, cursor_position - 1)
else
cursor_position = math.min(cursor_position + 1, 9)
end
end
function current_time_as_sec(time)
local sec = 0
for i = 1, 9 do
sec = sec + time_scale[i] * time[i]
end
return sec
end
function time_equal(lhs, rhs)
for i = 1, 9 do
if lhs[i] ~= rhs[i] then
return false
end
end
return true
end
function seek_to()
copy_history_to_last()
mp.commandv("osd-bar", "seek", current_time_as_sec(history[history_position]), "absolute")
--deduplicate consecutive timestamps
if #history == 1 or not time_equal(history[history_position], history[#history - 1]) then
history[#history + 1] = {}
history_position = #history
end
for i = 1, 9 do
history[#history][i] = 0
end
end
function backspace()
if history[history_position][cursor_position] ~= 0 then
copy_history_to_last()
history[#history][cursor_position] = 0
end
shift_cursor(true)
end
function history_move(up)
if up then
history_position = math.max(1, history_position - 1)
else
history_position = math.min(history_position + 1, #history)
end
end
local key_mappings = {
LEFT = function() shift_cursor(true) show_seeker() end,
RIGHT = function() shift_cursor(false) show_seeker() end,
UP = function() history_move(true) show_seeker() end,
DOWN = function() history_move(false) show_seeker() end,
BS = function() backspace() show_seeker() end,
ESC = function() set_inactive() end,
ENTER = function() seek_to() set_inactive() end
}
for i = 0, 9 do
local func = function() change_number(i) show_seeker() end
key_mappings[string.format("KP%d", i)] = func
key_mappings[string.format("%d", i)] = func
end
function set_active()
if not mp.get_property("seekable") then return end
-- find duration of the video and set cursor position accordingly
local duration = mp.get_property_number("duration")
if duration ~= nil then
for i = 1, 9 do
if duration > time_scale[i] then
cursor_position = i
break
end
end
end
for key, func in pairs(key_mappings) do
mp.add_forced_key_binding(key, "seek-to-"..key, func)
end
show_seeker()
timer = mp.add_periodic_timer(timer_duration, show_seeker)
active = true
end
function set_inactive()
mp.osd_message("")
for key, _ in pairs(key_mappings) do
mp.remove_key_binding("seek-to-"..key)
end
timer:kill()
active = false
end
function paste_timestamp()
-- get clipboard data
local clipboard = utils.subprocess({
args = { "xclip", "-selection", "clipboard", "-o" },
playback_only = false,
capture_stdout = true,
capture_stderr = true
})
-- error handling
if not clipboard.error then
timestamp = clipboard.stdout
else
msg.error("Error getting data from clipboard:")
msg.error(" stderr: " .. clipboard.stderr)
msg.error(" stdout: " .. clipboard.stdout)
return
end
-- find timestamp from clipboard
match = timestamp:match("%d?%d?:?%d%d:%d%d%.?%d*")
-- paste and seek to timestamp
if match ~= nil then
mp.osd_message("Timestamp pasted: " .. match)
mp.commandv("osd-bar", "seek", match, "absolute")
else
msg.warn("No pastable timestamp found!")
end
end
-- keybindings are set in input.conf
mp.add_key_binding(nil, "toggle-seeker", function() if active then set_inactive() else set_active() end end)
mp.add_key_binding(nil, "paste-timestamp", paste_timestamp)

View File

@@ -0,0 +1,147 @@
-- sponsorblock-minimal.lua
-- source: https://codeberg.org/jouni/mpv_sponsorblock_minimal
--
-- This script skips sponsored segments of YouTube videos
-- using data from https://github.com/ajayyy/SponsorBlock
local opt = require 'mp.options'
local utils = require 'mp.utils'
local ON = false
local ranges = nil
local options = {
server = "https://sponsor.ajay.app/api/skipSegments",
-- Categories to fetch and skip
categories = '"sponsor"',
-- Set this to "true" to use sha256HashPrefix instead of videoID
hash = ""
}
opt.read_options(options)
function get_ranges(youtube_id, url)
local luacurl_available, cURL = pcall(require,'cURL')
local res = nil
if not(luacurl_available) then -- if Lua-cURL is not available on this system
local sponsors = mp.command_native{
name = "subprocess",
capture_stdout = true,
playback_only = false,
args = {"curl", "-L", "-s", "-g", url}
}
res = sponsors.stdout
else -- otherwise use Lua-cURL (binding to libcurl)
local buf={}
local c = cURL.easy_init()
c:setopt_followlocation(1)
c:setopt_url(url)
c:setopt_writefunction(function(chunk) table.insert(buf,chunk); return true; end)
c:perform()
res = table.concat(buf)
end
if res then
local json = utils.parse_json(res)
if type(json) == "table" then
if options.hash == "true" then
for _, i in pairs(json) do
if i.videoID == youtube_id then
return i.segments
end
end
else
return json
end
end
end
return nil
end
function skip_ads(name,pos)
if pos then
for _, i in pairs(ranges) do
v = i.segment[2]
if i.segment[1] <= pos and v > pos then
--this message may sometimes be wrong
--it only seems to be a visual thing though
mp.osd_message(("[sponsorblock] skipping forward %ds"):format(math.floor(v-mp.get_property("time-pos"))))
--need to do the +0.01 otherwise mpv will start spamming skip sometimes
--example: https://www.youtube.com/watch?v=4ypMJzeNooo
mp.set_property("time-pos",v+0.01)
return
end
end
end
end
function file_loaded()
local video_path = mp.get_property("path", "")
local video_referer = string.match(mp.get_property("http-header-fields", ""), "Referer:([^,]+)") or ""
local urls = {
"ytdl://youtu%.be/([%w-_]+).*",
"ytdl://w?w?w?%.?youtube%.com/v/([%w-_]+).*",
"https?://youtu%.be/([%w-_]+).*",
"https?://w?w?w?%.?youtube%.com/v/([%w-_]+).*",
"/watch.*[?&]v=([%w-_]+).*",
"/embed/([%w-_]+).*",
"^ytdl://([%w-_]+)$",
"-([%w-_]+)%."
}
local youtube_id = nil
local purl = mp.get_property("metadata/by-key/PURL", "")
for i,url in ipairs(urls) do
youtube_id = youtube_id or string.match(video_path, url) or string.match(video_referer, url) or string.match(purl, url)
if youtube_id then break end
end
if not youtube_id or string.len(youtube_id) < 11 then return end
youtube_id = string.sub(youtube_id, 1, 11)
local url = ""
if options.hash == "true" then
local sha = mp.command_native{
name = "subprocess",
capture_stdout = true,
args = {"sha256sum"},
stdin_data = youtube_id
}
url = ("%s/%s?categories=[%s]"):format(options.server, string.sub(sha.stdout, 0, 4), options.categories)
else
url = ("%s?videoID=%s&categories=[%s]"):format(options.server, youtube_id, options.categories)
end
ranges = get_ranges(youtube_id, url)
if ranges then
ON = true
mp.add_key_binding("b","sponsorblock",toggle)
mp.observe_property("time-pos", "native", skip_ads)
end
end
function end_file()
if not ON then return end
mp.unobserve_property(skip_ads)
ranges = nil
ON = false
end
function toggle()
if ON then
mp.unobserve_property(skip_ads)
mp.osd_message("[sponsorblock] off")
ON = false
else
mp.observe_property("time-pos", "native", skip_ads)
mp.osd_message("[sponsorblock] on")
ON = true
end
end
mp.register_event("file-loaded", file_loaded)
mp.register_event("end-file", end_file)

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,190 +0,0 @@
local utils = require 'mp.utils'
-- 参数设置
local subtitlesPerPage = 10
local closeAfterLoad = true
local rate = 1.5
-- 全局变量和实用函数
local styleOn = mp.get_property("osd-ass-cc/0")
local subtitles = {}
local currentSlot = 1
local currentPage = 1
local maxPage = 1
local active = false
-- 控制列表
local subtitleControls = {
ESC = function() abort("") end,
e = function() abort("") end,
DOWN = function() jumpSlot(1) end,
UP = function() jumpSlot(-1) end,
j = function() jumpSlot(1) end,
k = function() jumpSlot(-1) end,
RIGHT = function() jumpPage(1) end,
LEFT = function() jumpPage(-1) end,
ENTER = function() loadSubtitle(currentSlot) end,
KP_ENTER = function() loadSubtitle(currentSlot) end
}
local subtitleFlags = {
DOWN = {repeatable = true},
UP = {repeatable = true},
RIGHT = {repeatable = true},
LEFT = {repeatable = true}
}
-- 激活自定义控件
function activateControls(name, controls, flags)
for key, func in pairs(controls) do
mp.add_forced_key_binding(key, name..key, func, flags[key])
end
end
-- 取消激活自定义控件
function deactivateControls(name, controls)
for key, _ in pairs(controls) do
mp.remove_key_binding(name..key)
end
end
-- 实用函数
function fileExists(path)
local f = io.open(path, "r")
if f ~= nil then
io.close(f)
return true
else
return false
end
end
-- 加载字幕列表
function listSubtitles()
subtitles = {}
local tracks = mp.get_property_native("track-list")
for _, track in ipairs(tracks) do
if track.type == "sub" then
table.insert(subtitles, track)
end
end
calcPages()
end
-- 计算当前页和总页数
function calcPages()
currentPage = math.floor((currentSlot - 1) / subtitlesPerPage) + 1
if currentPage == 0 then currentPage = 1 end
maxPage = math.floor((#subtitles - 1) / subtitlesPerPage) + 1
if maxPage == 0 then maxPage = 1 end
end
-- 获取指定页的字幕数量
function getAmountSubtitlesOnPage(page)
local n = subtitlesPerPage
if page == maxPage then n = #subtitles % subtitlesPerPage end
if n == 0 then n = subtitlesPerPage end
if #subtitles == 0 then n = 0 end
return n
end
-- 获取指定页的第一个字幕索引
function getFirstSlotOnPage(page)
return (page - 1) * subtitlesPerPage + 1
end
-- 获取指定页的最后一个字幕索引
function getLastSlotOnPage(page)
local endSlot = getFirstSlotOnPage(page) + getAmountSubtitlesOnPage(page) - 1
if endSlot > #subtitles then endSlot = #subtitles end
return endSlot
end
-- 跳到指定数量的字幕前或后
function jumpSlot(i)
currentSlot = currentSlot + i
local startSlot = getFirstSlotOnPage(currentPage)
local endSlot = getLastSlotOnPage(currentPage)
if currentSlot < startSlot then currentSlot = endSlot end
if currentSlot > endSlot then currentSlot = startSlot end
displaySubtitles()
end
-- 跳到指定数量的页前或后
function jumpPage(i)
local oldPos = currentSlot - getFirstSlotOnPage(currentPage) + 1
currentPage = currentPage + i
if currentPage < 1 then currentPage = maxPage + currentPage end
if currentPage > maxPage then currentPage = currentPage - maxPage end
local subtitlesOnPage = getAmountSubtitlesOnPage(currentPage)
if oldPos > subtitlesOnPage then oldPos = subtitlesOnPage end
currentSlot = getFirstSlotOnPage(currentPage) + oldPos - 1
displaySubtitles()
end
-- 显示当前页的字幕
function displaySubtitles()
-- 确定当前页的第一个和最后一个字幕索引
local startSlot = getFirstSlotOnPage(currentPage)
local endSlot = getLastSlotOnPage(currentPage)
-- 准备显示的文本并显示
local display = styleOn .. "{\\b1}Subtitles page " .. currentPage .. "/" .. maxPage .. ":{\\b0}"
for i = startSlot, endSlot do
local sub = subtitles[i]
local selection = ""
if i == currentSlot then
selection = "{\\b1}{\\c&H00FFFF&}>"
end
display = display .. "\n" .. selection .. i .. ": " .. (sub.title or sub.lang or sub.src) .. "{\\r}"
end
mp.osd_message(display, rate)
end
-- 加载指定的字幕
function loadSubtitle(slot)
if slot >= 1 and slot <= #subtitles then
local sub = subtitles[slot]
mp.set_property_native("sid", sub.id)
mp.osd_message(string.format("Loaded subtitle: %s", sub.title or sub.lang or sub.src), 2)
if closeAfterLoad then
abort(styleOn.."{\\c&H00FF00&}{\\b1}Successfully loaded subtitle:{\\r}\n"..(sub.title or sub.lang or sub.src))
end
else
abort(styleOn.."{\\c&H0000FF&}{\\b1}Can't find the subtitle at slot " .. slot)
end
end
-- 定时器
local timer = mp.add_periodic_timer(rate * 0.95, displaySubtitles)
timer:kill()
-- 终止程序
function abort(message)
mode = "none"
deactivateControls("subtitle", subtitleControls)
timer:kill()
mp.osd_message(message)
active = false
end
-- 处理字幕菜单的状态
function handler()
if active then
abort("")
else
activateControls("subtitle", subtitleControls, subtitleFlags)
listSubtitles()
displaySubtitles()
timer:resume()
active = true
end
end
-- 注册脚本消息
mp.register_script_message("subtitle-menu", handler)

926
mpv/scripts/thumbfast.lua Normal file
View File

@@ -0,0 +1,926 @@
-- thumbfast.lua
--
-- High-performance on-the-fly thumbnailer
--
-- Built for easy integration in third-party UIs.
--[[
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
]]
local options = {
-- Socket path (leave empty for auto)
socket = "",
-- Thumbnail path (leave empty for auto)
thumbnail = "",
-- Maximum thumbnail size in pixels (scaled down to fit)
-- Values are scaled when hidpi is enabled
max_height = 200,
max_width = 200,
-- Apply tone-mapping, no to disable
tone_mapping = "auto",
-- Overlay id
overlay_id = 42,
-- Spawn thumbnailer on file load for faster initial thumbnails
spawn_first = false,
-- Close thumbnailer process after an inactivity period in seconds, 0 to disable
quit_after_inactivity = 0,
-- Enable on network playback
network = false,
-- Enable on audio playback
audio = false,
-- Enable hardware decoding
hwdec = false,
-- Windows only: use native Windows API to write to pipe (requires LuaJIT)
direct_io = false,
-- Custom path to the mpv executable
mpv_path = "mpv"
}
mp.utils = require "mp.utils"
mp.options = require "mp.options"
mp.options.read_options(options, "thumbfast")
local properties = {}
local pre_0_30_0 = mp.command_native_async == nil
local pre_0_33_0 = true
function subprocess(args, async, callback)
callback = callback or function() end
if not pre_0_30_0 then
if async then
return mp.command_native_async({name = "subprocess", playback_only = true, args = args}, callback)
else
return mp.command_native({name = "subprocess", playback_only = false, capture_stdout = true, args = args})
end
else
if async then
return mp.utils.subprocess_detached({args = args}, callback)
else
return mp.utils.subprocess({args = args})
end
end
end
local winapi = {}
if options.direct_io then
local ffi_loaded, ffi = pcall(require, "ffi")
if ffi_loaded then
winapi = {
ffi = ffi,
C = ffi.C,
bit = require("bit"),
socket_wc = "",
-- WinAPI constants
CP_UTF8 = 65001,
GENERIC_WRITE = 0x40000000,
OPEN_EXISTING = 3,
FILE_FLAG_WRITE_THROUGH = 0x80000000,
FILE_FLAG_NO_BUFFERING = 0x20000000,
PIPE_NOWAIT = ffi.new("unsigned long[1]", 0x00000001),
INVALID_HANDLE_VALUE = ffi.cast("void*", -1),
-- don't care about how many bytes WriteFile wrote, so allocate something to store the result once
_lpNumberOfBytesWritten = ffi.new("unsigned long[1]"),
}
-- cache flags used in run() to avoid bor() call
winapi._createfile_pipe_flags = winapi.bit.bor(winapi.FILE_FLAG_WRITE_THROUGH, winapi.FILE_FLAG_NO_BUFFERING)
ffi.cdef[[
void* __stdcall CreateFileW(const wchar_t *lpFileName, unsigned long dwDesiredAccess, unsigned long dwShareMode, void *lpSecurityAttributes, unsigned long dwCreationDisposition, unsigned long dwFlagsAndAttributes, void *hTemplateFile);
bool __stdcall WriteFile(void *hFile, const void *lpBuffer, unsigned long nNumberOfBytesToWrite, unsigned long *lpNumberOfBytesWritten, void *lpOverlapped);
bool __stdcall CloseHandle(void *hObject);
bool __stdcall SetNamedPipeHandleState(void *hNamedPipe, unsigned long *lpMode, unsigned long *lpMaxCollectionCount, unsigned long *lpCollectDataTimeout);
int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
]]
winapi.MultiByteToWideChar = function(MultiByteStr)
if MultiByteStr then
local utf16_len = winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, MultiByteStr, -1, nil, 0)
if utf16_len > 0 then
local utf16_str = winapi.ffi.new("wchar_t[?]", utf16_len)
if winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, MultiByteStr, -1, utf16_str, utf16_len) > 0 then
return utf16_str
end
end
end
return ""
end
else
options.direct_io = false
end
end
local file = nil
local file_bytes = 0
local spawned = false
local disabled = false
local force_disabled = false
local spawn_waiting = false
local spawn_working = false
local script_written = false
local dirty = false
local x = nil
local y = nil
local last_x = x
local last_y = y
local last_seek_time = nil
local effective_w = options.max_width
local effective_h = options.max_height
local real_w = nil
local real_h = nil
local last_real_w = nil
local last_real_h = nil
local script_name = nil
local show_thumbnail = false
local filters_reset = {["lavfi-crop"]=true, ["crop"]=true}
local filters_runtime = {["hflip"]=true, ["vflip"]=true}
local filters_all = {["hflip"]=true, ["vflip"]=true, ["lavfi-crop"]=true, ["crop"]=true}
local tone_mappings = {["none"]=true, ["clip"]=true, ["linear"]=true, ["gamma"]=true, ["reinhard"]=true, ["hable"]=true, ["mobius"]=true}
local last_tone_mapping = nil
local last_vf_reset = ""
local last_vf_runtime = ""
local last_rotate = 0
local par = ""
local last_par = ""
local last_has_vid = 0
local has_vid = 0
local file_timer = nil
local file_check_period = 1/60
local allow_fast_seek = true
local client_script = [=[
#!/usr/bin/env bash
MPV_IPC_FD=0; MPV_IPC_PATH="%s"
trap "kill 0" EXIT
while [[ $# -ne 0 ]]; do case $1 in --mpv-ipc-fd=*) MPV_IPC_FD=${1/--mpv-ipc-fd=/} ;; esac; shift; done
if echo "print-text thumbfast" >&"$MPV_IPC_FD"; then echo -n > "$MPV_IPC_PATH"; tail -f "$MPV_IPC_PATH" >&"$MPV_IPC_FD" & while read -r -u "$MPV_IPC_FD" 2>/dev/null; do :; done; fi
]=]
local function get_os()
local raw_os_name = ""
if jit and jit.os and jit.arch then
raw_os_name = jit.os
else
if package.config:sub(1,1) == "\\" then
-- Windows
local env_OS = os.getenv("OS")
if env_OS then
raw_os_name = env_OS
end
else
raw_os_name = subprocess({"uname", "-s"}).stdout
end
end
raw_os_name = (raw_os_name):lower()
local os_patterns = {
["windows"] = "windows",
["linux"] = "linux",
["osx"] = "darwin",
["mac"] = "darwin",
["darwin"] = "darwin",
["^mingw"] = "windows",
["^cygwin"] = "windows",
["bsd$"] = "darwin",
["sunos"] = "darwin"
}
-- Default to linux
local str_os_name = "linux"
for pattern, name in pairs(os_patterns) do
if raw_os_name:match(pattern) then
str_os_name = name
break
end
end
return str_os_name
end
local os_name = mp.get_property("platform") or get_os()
local path_separator = os_name == "windows" and "\\" or "/"
if options.socket == "" then
if os_name == "windows" then
options.socket = "thumbfast"
else
options.socket = "/tmp/thumbfast"
end
end
if options.thumbnail == "" then
if os_name == "windows" then
options.thumbnail = os.getenv("TEMP").."\\thumbfast.out"
else
options.thumbnail = "/tmp/thumbfast.out"
end
end
local unique = mp.utils.getpid()
options.socket = options.socket .. unique
options.thumbnail = options.thumbnail .. unique
if options.direct_io then
if os_name == "windows" then
winapi.socket_wc = winapi.MultiByteToWideChar("\\\\.\\pipe\\" .. options.socket)
end
if winapi.socket_wc == "" then
options.direct_io = false
end
end
local mpv_path = options.mpv_path
if mpv_path == "mpv" and os_name == "darwin" and unique then
-- TODO: look into ~~osxbundle/
mpv_path = string.gsub(subprocess({"ps", "-o", "comm=", "-p", tostring(unique)}).stdout, "[\n\r]", "")
if mpv_path ~= "mpv" then
mpv_path = string.gsub(mpv_path, "/mpv%-bundle$", "/mpv")
local mpv_bin = mp.utils.file_info("/usr/local/mpv")
if mpv_bin and mpv_bin.is_file then
mpv_path = "/usr/local/mpv"
else
local mpv_app = mp.utils.file_info("/Applications/mpv.app/Contents/MacOS/mpv")
if mpv_app and mpv_app.is_file then
mp.msg.warn("symlink mpv to fix Dock icons: `sudo ln -s /Applications/mpv.app/Contents/MacOS/mpv /usr/local/mpv`")
else
mp.msg.warn("drag to your Applications folder and symlink mpv to fix Dock icons: `sudo ln -s /Applications/mpv.app/Contents/MacOS/mpv /usr/local/mpv`")
end
end
end
end
local function vo_tone_mapping()
local passes = mp.get_property_native("vo-passes")
if passes and passes["fresh"] then
for k, v in pairs(passes["fresh"]) do
for k2, v2 in pairs(v) do
if k2 == "desc" and v2 then
local tone_mapping = string.match(v2, "([0-9a-z.-]+) tone map")
if tone_mapping then
return tone_mapping
end
end
end
end
end
end
local function vf_string(filters, full)
local vf = ""
local vf_table = properties["vf"]
if vf_table and #vf_table > 0 then
for i = #vf_table, 1, -1 do
if filters[vf_table[i].name] then
local args = ""
for key, value in pairs(vf_table[i].params) do
if args ~= "" then
args = args .. ":"
end
args = args .. key .. "=" .. value
end
vf = vf .. vf_table[i].name .. "=" .. args .. ","
end
end
end
if (full and options.tone_mapping ~= "no") or options.tone_mapping == "auto" then
if properties["video-params"] and properties["video-params"]["primaries"] == "bt.2020" then
local tone_mapping = options.tone_mapping
if tone_mapping == "auto" then
tone_mapping = last_tone_mapping or properties["tone-mapping"]
if tone_mapping == "auto" and properties["current-vo"] == "gpu-next" then
tone_mapping = vo_tone_mapping()
end
end
if not tone_mappings[tone_mapping] then
tone_mapping = "hable"
end
last_tone_mapping = tone_mapping
vf = vf .. "zscale=transfer=linear,format=gbrpf32le,tonemap="..tone_mapping..",zscale=transfer=bt709,"
end
end
if full then
vf = vf.."scale=w="..effective_w..":h="..effective_h..par..",pad=w="..effective_w..":h="..effective_h..":x=-1:y=-1,format=bgra"
end
return vf
end
local function calc_dimensions()
local width = properties["video-out-params"] and properties["video-out-params"]["dw"]
local height = properties["video-out-params"] and properties["video-out-params"]["dh"]
if not width or not height then return end
local scale = properties["display-hidpi-scale"] or 1
if width / height > options.max_width / options.max_height then
effective_w = math.floor(options.max_width * scale + 0.5)
effective_h = math.floor(height / width * effective_w + 0.5)
else
effective_h = math.floor(options.max_height * scale + 0.5)
effective_w = math.floor(width / height * effective_h + 0.5)
end
local v_par = properties["video-out-params"] and properties["video-out-params"]["par"] or 1
if v_par == 1 then
par = ":force_original_aspect_ratio=decrease"
else
par = ""
end
end
local info_timer = nil
local function info(w, h)
local rotate = properties["video-params"] and properties["video-params"]["rotate"]
local image = properties["current-tracks/video"] and properties["current-tracks/video"]["image"]
local albumart = image and properties["current-tracks/video"]["albumart"]
disabled = (w or 0) == 0 or (h or 0) == 0 or
has_vid == 0 or
(properties["demuxer-via-network"] and not options.network) or
(albumart and not options.audio) or
(image and not albumart) or
force_disabled
if info_timer then
info_timer:kill()
info_timer = nil
elseif has_vid == 0 or (rotate == nil and not disabled) then
info_timer = mp.add_timeout(0.05, function() info(w, h) end)
end
local json, err = mp.utils.format_json({width=w, height=h, disabled=disabled, available=true, socket=options.socket, thumbnail=options.thumbnail, overlay_id=options.overlay_id})
if pre_0_30_0 then
mp.command_native({"script-message", "thumbfast-info", json})
else
mp.command_native_async({"script-message", "thumbfast-info", json}, function() end)
end
end
local function remove_thumbnail_files()
if file then
file:close()
file = nil
file_bytes = 0
end
os.remove(options.thumbnail)
os.remove(options.thumbnail..".bgra")
end
local activity_timer
local function spawn(time)
if disabled then return end
local path = properties["path"]
if path == nil then return end
if options.quit_after_inactivity > 0 then
if show_thumbnail or activity_timer:is_enabled() then
activity_timer:kill()
end
activity_timer:resume()
end
local open_filename = properties["stream-open-filename"]
local ytdl = open_filename and properties["demuxer-via-network"] and path ~= open_filename
if ytdl then
path = open_filename
end
remove_thumbnail_files()
local vid = properties["vid"]
has_vid = vid or 0
local args = {
mpv_path, "--no-config", "--msg-level=all=no", "--idle", "--pause", "--keep-open=always", "--really-quiet", "--no-terminal",
"--load-scripts=no", "--osc=no", "--ytdl=no", "--load-stats-overlay=no", "--load-osd-console=no", "--load-auto-profiles=no",
"--edition="..(properties["edition"] or "auto"), "--vid="..(vid or "auto"), "--no-sub", "--no-audio",
"--start="..time, allow_fast_seek and "--hr-seek=no" or "--hr-seek=yes",
"--ytdl-format=worst", "--demuxer-readahead-secs=0", "--demuxer-max-bytes=128KiB",
"--vd-lavc-skiploopfilter=all", "--vd-lavc-software-fallback=1", "--vd-lavc-fast", "--vd-lavc-threads=2", "--hwdec="..(options.hwdec and "auto" or "no"),
"--vf="..vf_string(filters_all, true),
"--sws-scaler=fast-bilinear",
"--video-rotate="..last_rotate,
"--ovc=rawvideo", "--of=image2", "--ofopts=update=1", "--o="..options.thumbnail
}
if not pre_0_30_0 then
table.insert(args, "--sws-allow-zimg=no")
end
if os_name == "darwin" and properties["macos-app-activation-policy"] then
table.insert(args, "--macos-app-activation-policy=accessory")
end
if os_name == "windows" or pre_0_33_0 then
table.insert(args, "--input-ipc-server="..options.socket)
elseif not script_written then
local client_script_path = options.socket..".run"
local script = io.open(client_script_path, "w+")
if script == nil then
mp.msg.error("client script write failed")
return
else
script_written = true
script:write(string.format(client_script, options.socket))
script:close()
subprocess({"chmod", "+x", client_script_path}, true)
table.insert(args, "--scripts="..client_script_path)
end
else
local client_script_path = options.socket..".run"
table.insert(args, "--scripts="..client_script_path)
end
table.insert(args, "--")
table.insert(args, path)
spawned = true
spawn_waiting = true
subprocess(args, true,
function(success, result)
if spawn_waiting and (success == false or (result.status ~= 0 and result.status ~= -2)) then
spawned = false
spawn_waiting = false
options.tone_mapping = "no"
mp.msg.error("mpv subprocess create failed")
if not spawn_working then -- notify users of required configuration
if options.mpv_path == "mpv" then
if properties["current-vo"] == "libmpv" then
if options.mpv_path == mpv_path then -- attempt to locate ImPlay
mpv_path = "ImPlay"
spawn(time)
else -- ImPlay not in path
if os_name ~= "darwin" then
force_disabled = true
info(real_w or effective_w, real_h or effective_h)
end
mp.commandv("show-text", "thumbfast: ERROR! cannot create mpv subprocess", 5000)
mp.commandv("script-message-to", "implay", "show-message", "thumbfast initial setup", "Set mpv_path=PATH_TO_ImPlay in thumbfast config:\n" .. string.gsub(mp.command_native({"expand-path", "~~/script-opts/thumbfast.conf"}), "[/\\]", path_separator).."\nand restart ImPlay")
end
else
mp.commandv("show-text", "thumbfast: ERROR! cannot create mpv subprocess", 5000)
if os_name == "windows" then
mp.commandv("script-message-to", "mpvnet", "show-text", "thumbfast: ERROR! install standalone mpv, see README", 5000, 20)
mp.commandv("script-message", "mpv.net", "show-text", "thumbfast: ERROR! install standalone mpv, see README", 5000, 20)
end
end
else
mp.commandv("show-text", "thumbfast: ERROR! cannot create mpv subprocess", 5000)
-- found ImPlay but not defined in config
mp.commandv("script-message-to", "implay", "show-message", "thumbfast", "Set mpv_path=PATH_TO_ImPlay in thumbfast config:\n" .. string.gsub(mp.command_native({"expand-path", "~~/script-opts/thumbfast.conf"}), "[/\\]", path_separator).."\nand restart ImPlay")
end
end
elseif success == true and (result.status == 0 or result.status == -2) then
if not spawn_working and properties["current-vo"] == "libmpv" and options.mpv_path ~= mpv_path then
mp.commandv("script-message-to", "implay", "show-message", "thumbfast initial setup", "Set mpv_path=ImPlay in thumbfast config:\n" .. string.gsub(mp.command_native({"expand-path", "~~/script-opts/thumbfast.conf"}), "[/\\]", path_separator).."\nand restart ImPlay")
end
spawn_working = true
spawn_waiting = false
end
end
)
end
local function run(command)
if not spawned then return end
if options.direct_io then
local hPipe = winapi.C.CreateFileW(winapi.socket_wc, winapi.GENERIC_WRITE, 0, nil, winapi.OPEN_EXISTING, winapi._createfile_pipe_flags, nil)
if hPipe ~= winapi.INVALID_HANDLE_VALUE then
local buf = command .. "\n"
winapi.C.SetNamedPipeHandleState(hPipe, winapi.PIPE_NOWAIT, nil, nil)
winapi.C.WriteFile(hPipe, buf, #buf + 1, winapi._lpNumberOfBytesWritten, nil)
winapi.C.CloseHandle(hPipe)
end
return
end
local command_n = command.."\n"
if os_name == "windows" then
if file and file_bytes + #command_n >= 4096 then
file:close()
file = nil
file_bytes = 0
end
if not file then
file = io.open("\\\\.\\pipe\\"..options.socket, "r+b")
end
elseif pre_0_33_0 then
subprocess({"/usr/bin/env", "sh", "-c", "echo '" .. command .. "' | socat - " .. options.socket})
return
elseif not file then
file = io.open(options.socket, "r+")
end
if file then
file_bytes = file:seek("end")
file:write(command_n)
file:flush()
end
end
local function draw(w, h, script)
if not w or not show_thumbnail then return end
if x ~= nil then
if pre_0_30_0 then
mp.command_native({"overlay-add", options.overlay_id, x, y, options.thumbnail..".bgra", 0, "bgra", w, h, (4*w)})
else
mp.command_native_async({"overlay-add", options.overlay_id, x, y, options.thumbnail..".bgra", 0, "bgra", w, h, (4*w)}, function() end)
end
elseif script then
local json, err = mp.utils.format_json({width=w, height=h, x=x, y=y, socket=options.socket, thumbnail=options.thumbnail, overlay_id=options.overlay_id})
mp.commandv("script-message-to", script, "thumbfast-render", json)
end
end
local function real_res(req_w, req_h, filesize)
local count = filesize / 4
local diff = (req_w * req_h) - count
if (properties["video-params"] and properties["video-params"]["rotate"] or 0) % 180 == 90 then
req_w, req_h = req_h, req_w
end
if diff == 0 then
return req_w, req_h
else
local threshold = 5 -- throw out results that change too much
local long_side, short_side = req_w, req_h
if req_h > req_w then
long_side, short_side = req_h, req_w
end
for a = short_side, short_side - threshold, -1 do
if count % a == 0 then
local b = count / a
if long_side - b < threshold then
if req_h < req_w then return b, a else return a, b end
end
end
end
return nil
end
end
local function move_file(from, to)
if os_name == "windows" then
os.remove(to)
end
-- move the file because it can get overwritten while overlay-add is reading it, and crash the player
os.rename(from, to)
end
local function seek(fast)
if last_seek_time then
run("async seek " .. last_seek_time .. (fast and " absolute+keyframes" or " absolute+exact"))
end
end
local seek_period = 3/60
local seek_period_counter = 0
local seek_timer
seek_timer = mp.add_periodic_timer(seek_period, function()
if seek_period_counter == 0 then
seek(allow_fast_seek)
seek_period_counter = 1
else
if seek_period_counter == 2 then
if allow_fast_seek then
seek_timer:kill()
seek()
end
else seek_period_counter = seek_period_counter + 1 end
end
end)
seek_timer:kill()
local function request_seek()
if seek_timer:is_enabled() then
seek_period_counter = 0
else
seek_timer:resume()
seek(allow_fast_seek)
seek_period_counter = 1
end
end
local function check_new_thumb()
-- the slave might start writing to the file after checking existance and
-- validity but before actually moving the file, so move to a temporary
-- location before validity check to make sure everything stays consistant
-- and valid thumbnails don't get overwritten by invalid ones
local tmp = options.thumbnail..".tmp"
move_file(options.thumbnail, tmp)
local finfo = mp.utils.file_info(tmp)
if not finfo then return false end
spawn_waiting = false
local w, h = real_res(effective_w, effective_h, finfo.size)
if w then -- only accept valid thumbnails
move_file(tmp, options.thumbnail..".bgra")
real_w, real_h = w, h
if real_w and (real_w ~= last_real_w or real_h ~= last_real_h) then
last_real_w, last_real_h = real_w, real_h
info(real_w, real_h)
end
if not show_thumbnail then
file_timer:kill()
end
return true
end
return false
end
file_timer = mp.add_periodic_timer(file_check_period, function()
if check_new_thumb() then
draw(real_w, real_h, script_name)
end
end)
file_timer:kill()
local function clear()
file_timer:kill()
seek_timer:kill()
if options.quit_after_inactivity > 0 then
if show_thumbnail or activity_timer:is_enabled() then
activity_timer:kill()
end
activity_timer:resume()
end
last_seek_time = nil
show_thumbnail = false
last_x = nil
last_y = nil
if script_name then return end
if pre_0_30_0 then
mp.command_native({"overlay-remove", options.overlay_id})
else
mp.command_native_async({"overlay-remove", options.overlay_id}, function() end)
end
end
local function quit()
activity_timer:kill()
if show_thumbnail then
activity_timer:resume()
return
end
run("quit")
spawned = false
real_w, real_h = nil, nil
clear()
end
activity_timer = mp.add_timeout(options.quit_after_inactivity, quit)
activity_timer:kill()
local function thumb(time, r_x, r_y, script)
if disabled then return end
time = tonumber(time)
if time == nil then return end
if r_x == "" or r_y == "" then
x, y = nil, nil
else
x, y = math.floor(r_x + 0.5), math.floor(r_y + 0.5)
end
script_name = script
if last_x ~= x or last_y ~= y or not show_thumbnail then
show_thumbnail = true
last_x = x
last_y = y
draw(real_w, real_h, script)
end
if options.quit_after_inactivity > 0 then
if show_thumbnail or activity_timer:is_enabled() then
activity_timer:kill()
end
activity_timer:resume()
end
if time == last_seek_time then return end
last_seek_time = time
if not spawned then spawn(time) end
request_seek()
if not file_timer:is_enabled() then file_timer:resume() end
end
local function watch_changes()
if not dirty or not properties["video-out-params"] then return end
dirty = false
local old_w = effective_w
local old_h = effective_h
calc_dimensions()
local vf_reset = vf_string(filters_reset)
local rotate = properties["video-rotate"] or 0
local resized = old_w ~= effective_w or
old_h ~= effective_h or
last_vf_reset ~= vf_reset or
(last_rotate % 180) ~= (rotate % 180) or
par ~= last_par
if resized then
last_rotate = rotate
info(effective_w, effective_h)
elseif last_has_vid ~= has_vid and has_vid ~= 0 then
info(effective_w, effective_h)
end
if spawned then
if resized then
-- mpv doesn't allow us to change output size
local seek_time = last_seek_time
run("quit")
clear()
spawned = false
spawn(seek_time or mp.get_property_number("time-pos", 0))
file_timer:resume()
else
if rotate ~= last_rotate then
run("set video-rotate "..rotate)
end
local vf_runtime = vf_string(filters_runtime)
if vf_runtime ~= last_vf_runtime then
run("vf set "..vf_string(filters_all, true))
last_vf_runtime = vf_runtime
end
end
else
last_vf_runtime = vf_string(filters_runtime)
end
last_vf_reset = vf_reset
last_rotate = rotate
last_par = par
last_has_vid = has_vid
if not spawned and not disabled and options.spawn_first and resized then
spawn(mp.get_property_number("time-pos", 0))
file_timer:resume()
end
end
local function update_property(name, value)
properties[name] = value
end
local function update_property_dirty(name, value)
properties[name] = value
dirty = true
if name == "tone-mapping" then
last_tone_mapping = nil
end
end
local function update_tracklist(name, value)
-- current-tracks shim
for _, track in ipairs(value) do
if track.type == "video" and track.selected then
properties["current-tracks/video"] = track
return
end
end
end
local function sync_changes(prop, val)
update_property(prop, val)
if val == nil then return end
if type(val) == "boolean" then
if prop == "vid" then
has_vid = 0
last_has_vid = 0
info(effective_w, effective_h)
clear()
return
end
val = val and "yes" or "no"
end
if prop == "vid" then
has_vid = 1
end
if not spawned then return end
run("set "..prop.." "..val)
dirty = true
end
local function file_load()
clear()
spawned = false
real_w, real_h = nil, nil
last_real_w, last_real_h = nil, nil
last_tone_mapping = nil
last_seek_time = nil
if info_timer then
info_timer:kill()
info_timer = nil
end
calc_dimensions()
info(effective_w, effective_h)
end
local function shutdown()
run("quit")
remove_thumbnail_files()
if os_name ~= "windows" then
os.remove(options.socket)
os.remove(options.socket..".run")
end
end
local function on_duration(prop, val)
allow_fast_seek = (val or 30) >= 30
end
mp.observe_property("current-tracks/video", "native", function(name, value)
if pre_0_33_0 then
mp.unobserve_property(update_tracklist)
pre_0_33_0 = false
end
update_property(name, value)
end)
mp.observe_property("track-list", "native", update_tracklist)
mp.observe_property("display-hidpi-scale", "native", update_property_dirty)
mp.observe_property("video-out-params", "native", update_property_dirty)
mp.observe_property("video-params", "native", update_property_dirty)
mp.observe_property("vf", "native", update_property_dirty)
mp.observe_property("tone-mapping", "native", update_property_dirty)
mp.observe_property("demuxer-via-network", "native", update_property)
mp.observe_property("stream-open-filename", "native", update_property)
mp.observe_property("macos-app-activation-policy", "native", update_property)
mp.observe_property("current-vo", "native", update_property)
mp.observe_property("video-rotate", "native", update_property)
mp.observe_property("path", "native", update_property)
mp.observe_property("vid", "native", sync_changes)
mp.observe_property("edition", "native", sync_changes)
mp.observe_property("duration", "native", on_duration)
mp.register_script_message("thumb", thumb)
mp.register_script_message("clear", clear)
mp.register_event("file-loaded", file_load)
mp.register_event("shutdown", shutdown)
mp.register_idle(watch_changes)

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,418 @@
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//!DESC NNEDI3 (double_y, nns128, win8x4)
//!HOOK LUMA
//!BIND HOOKED
//!SAVE nnedi3_int
//!WHEN HOOKED.h OUTPUT.h / 0.707106 <
float nnedi3(vec4 samples[8]) {
float sum = 0.0, sumsq = 0.0;
for (int i = 0; i < 8; i++) {
sum += dot(samples[i], vec4(1.0));
sumsq += dot(samples[i], samples[i]);
}
float mstd0 = sum / 32.0;
float mstd1 = sumsq / 32.0 - mstd0 * mstd0;
float mstd2 = mix(0.0, inversesqrt(mstd1), mstd1 >= 1.192092896e-7);
mstd1 *= mstd2;
float vsum = 0.0, wsum = 0.0, sum1, sum2;
#define T(x) intBitsToFloat(x)
#define W(i,w0,w1,w2,w3) dot(samples[i],vec4(T(w0),T(w1),T(w2),T(w3)))
#define WS(w0,w1) sum1 = exp(sum1 * mstd2 + T(w0)); sum2 = sum2 * mstd2 + T(w1); wsum += sum1; vsum += sum1*(sum2/(1.0+abs(sum2)));
sum1=W(0,-1106336704,-1104338237,1041734649,-1112016931)+W(1,-1134422686,-1108550970,-1135080854,-1117701445)+W(2,-1097058997,1036063029,1053379177,-1099451832)+W(3,-1096794255,1068454954,1068510503,-1092648385)+W(4,-1096428577,1045547931,-1114733521,-1101312270)+W(5,-1108910446,-1102009308,-1146436468,-1118387353)+W(6,-1110459731,-1122481515,-1107441476,-1118789516)+W(7,-1101174078,1017740065,-1113618698,-1107281979);sum2=W(0,-1107960738,1034572820,-1105088633,-1147785184)+W(1,1022891960,1003346080,-1103397515,1035529310)+W(2,-1112828174,-1096749055,1056062200,-1105585021)+W(3,-1099542471,1067566060,-1127174872,1034766166)+W(4,1028527356,-1090311143,1048792675,-1117109292)+W(5,-1124169384,1028295012,-1106700271,-1116900804)+W(6,1003609248,-1101382023,1033154740,-1121486356)+W(7,1019646072,-1102277943,1037356874,-1114899026);WS(-1075683047,-1087125913);
sum1=W(0,1042687663,1052977914,-1087267578,1041384601)+W(1,1034752002,1046022844,-1097639380,1034807969)+W(2,1020877136,1051043629,-1087388173,1037740431)+W(3,1043598702,1049374510,-1095656786,1044538321)+W(4,1032834596,1044576234,-1108370107,-1113942663)+W(5,1049059763,-1108783446,-1101488315,1043415765)+W(6,1041786741,-1105784362,-1111228387,1011031587)+W(7,1050972591,-1089957133,-1108747496,1034104676);sum2=W(0,-1129327146,-1112916736,-1109246006,-1168639863)+W(1,-1149557934,-1120018795,1012425107,-1122303521)+W(2,1027469999,-1105442406,1044505132,-1114911422)+W(3,-1116270499,1056936993,1054092693,-1109477794)+W(4,-1107094547,1036431709,1015080154,-1122292075)+W(5,-1114668504,1029410453,-1102188513,1038663029)+W(6,-1136313139,-1126491682,-1123974759,-1124857486)+W(7,-1115408970,-1112281372,-1115235380,1004657207);WS(1042212664,-1102203684);
sum1=W(0,-1140902818,1040147851,1035472140,-1111794429)+W(1,1019874102,-1104962202,1045102086,1033944684)+W(2,-1138465404,-1102798136,1044852023,-1122108180)+W(3,1041713132,-1085739950,1052255697,1042129278)+W(4,1031911135,-1090423514,1050093153,1026181805)+W(5,1032244040,-1096835716,-1114874577,1045351411)+W(6,-1122713961,1015091005,-1125530488,1045226448)+W(7,1032066151,-1100137137,1025859399,1037723887);sum2=W(0,1025219442,-1109152196,1026944460,-1136900198)+W(1,-1119436548,-1122141349,1040314652,-1112897189)+W(2,1041363772,1032935700,-1124096755,-1144192892)+W(3,1026037858,-1095545125,-1132954458,1046665648)+W(4,-1106963956,1029288712,1063106013,-1112667488)+W(5,-1148187164,1048235476,1044093468,-1091150222)+W(6,-1115265228,1017807431,-1119277141,-1098670428)+W(7,1027834104,-1124373883,-1115291573,-1099776205);WS(-1106435384,1038338229);
sum1=W(0,1040095954,1057302312,-1085504617,1038469973)+W(1,1019822615,1048464174,-1109673285,1008999077)+W(2,1037825128,1048602738,-1088007186,1047759857)+W(3,1041126536,1046177110,-1089584127,1042217259)+W(4,1042659628,-1113571175,-1112427435,-1122205838)+W(5,1046281616,1010729037,-1099904421,1042535855)+W(6,1025627498,-1116720143,985851280,1020820192)+W(7,1052688116,-1090676327,-1109333660,1034203799);sum2=W(0,1016257202,1059204215,1078138204,1045786159)+W(1,1025056091,1059357388,1057901024,-1115583727)+W(2,-1123344133,-1096239491,-1075026282,1040463834)+W(3,-1117490597,-1080318626,-1073900782,1043123901)+W(4,-1139226916,-1097775023,1041808545,1021989454)+W(5,-1121712633,-1121076469,1040778731,-1105966927)+W(6,1032149092,-1108589001,1040543247,1015040126)+W(7,1018740994,1042934709,1013253724,-1147555881);WS(-1079558823,-1098708322);
sum1=W(0,-1107155318,-1102044491,-1157836704,1018716763)+W(1,1025234303,-1098872409,1050456336,1032647774)+W(2,1015859078,-1087610848,1055919296,1043448582)+W(3,1036194249,-1086405173,1051086989,1041211303)+W(4,-1109510417,1049149960,1049231261,1032229161)+W(5,-1106597869,-1113006787,1047976577,-1113988824)+W(6,-1106784003,1034815041,1037659280,-1114873522)+W(7,-1107821257,-1109243348,1045770027,-1115826050);sum2=W(0,-1115121954,1038073794,-1128914993,-1116577465)+W(1,1012713185,-1114116718,1041575276,-1124395325)+W(2,-1120959275,1048906430,1074552079,1055266270)+W(3,979525395,-1089285214,-1076455267,1060162115)+W(4,1031308048,1044939824,-1081125046,-1098098687)+W(5,1023425822,960279117,-1109266711,1021768571)+W(6,1008898041,-1114246838,1028966618,-1124862202)+W(7,1015643115,-1116674868,-1116558128,1013382601);WS(1045132600,-1120782135);
sum1=W(0,-1105751784,1057393815,-1105555137,-1117651397)+W(1,-1105178898,1048859946,-1097544977,1030868229)+W(2,-1104184899,1059464001,-1093321826,-1113548192)+W(3,-1114219853,1046945589,-1096850414,-1114482291)+W(4,-1110381909,-1115358437,1045680426,-1100710867)+W(5,1038688878,-1101266388,1054674458,-1101910270)+W(6,-1129240105,1006928425,1040711722,-1109195062)+W(7,1028338913,1001553277,1051440502,-1106616547);sum2=W(0,1017265392,1041015042,-1100279165,1015388608)+W(1,-1109811903,1031690548,-1110095441,-1118750728)+W(2,1023756444,1041543835,-1121800962,1018680528)+W(3,-1113627340,1061785433,1052269299,-1143924414)+W(4,1014378799,-1112539854,1027655784,-1099334823)+W(5,-1145950526,1033767962,-1103181542,1020584168)+W(6,-1129429444,-1111764061,-1110834939,-1108053853)+W(7,1013677319,-1098545742,-1106577514,1036964648);WS(1052573852,-1122511817);
sum1=W(0,-1122539822,-1107197216,-1123108403,1051517474)+W(1,1036520122,-1104137920,1038549849,1023654291)+W(2,-1150669710,-1095755763,1032946604,1039184399)+W(3,-1131456914,-1089160552,1050538028,1041388597)+W(4,1027717464,-1090293588,1052989852,-1168884669)+W(5,1032118773,-1090056564,1057974832,1033029075)+W(6,1021054902,-1092174087,1053464075,1028526105)+W(7,1030809195,-1086001910,1057808582,1041880934);sum2=W(0,-1085894681,-1108201039,1070882268,-1081052443)+W(1,1038192816,-1090848333,-1093216289,-1102549623)+W(2,-1098445483,1052221636,1067999858,-1087793608)+W(3,-1102898046,1071505414,1073865984,-1090403840)+W(4,1008806191,-1098981857,1058878464,-1095780376)+W(5,1050638036,-1086351349,-1083525828,1055133376)+W(6,-1102617523,-1096799400,-1107159037,-1096503933)+W(7,1057325981,-1088620184,-1083206959,1053790412);WS(-1073219892,-1080326418);
sum1=W(0,-1114077580,-1101602915,1057495924,-1151047116)+W(1,-1142635506,-1103425331,1053716920,-1114784094)+W(2,-1142955026,-1090278522,1055741332,-1111276924)+W(3,-1123237842,-1092662145,1051447237,-1121668701)+W(4,1038107057,-1091646784,1052494629,1000704387)+W(5,-1103324917,-1114692451,1049044089,-1109204280)+W(6,1026598572,-1101848592,1043005848,1010568075)+W(7,-1095875035,1038718196,1047828379,-1156952092);sum2=W(0,-1121663397,-1095443331,-1067370736,1005231721)+W(1,-1116542136,1050195534,-1071776975,974104521)+W(2,1042431779,-1123573301,1068672794,-1111985184)+W(3,1037730633,-1100504352,1077012119,1047585075)+W(4,1010053773,1043186658,1070664889,1016528922)+W(5,-1137348615,-1102861372,1045361006,-1109020232)+W(6,1028087910,-1110454800,-1123945395,1037668055)+W(7,-1119025600,1040229501,1027642294,-1117277443);WS(-1130027456,1047744266);
sum1=W(0,1030328637,-1103440100,1050534604,-1130350917)+W(1,-1100312969,1043447132,1038395889,-1105733872)+W(2,1036569044,-1096543805,1037345619,1043114871)+W(3,1044449278,-1093151398,-1106526388,1022399622)+W(4,-1106699970,1024264999,-1115006287,1020228332)+W(5,1046212150,-1115860524,1035372917,1024836117)+W(6,-1104762293,1041344218,980910400,-1123108872)+W(7,-1124975021,1032410566,1044066628,-1112803412);sum2=W(0,1029880722,1033391383,-1137819024,-1114516031)+W(1,-1098453144,1041649400,-1137377888,1025620716)+W(2,1029103498,-1095624145,1040796761,1035240799)+W(3,1067660000,-1082091368,-1080643124,1066795978)+W(4,-1094604015,1056223691,-1102259819,-1098376459)+W(5,1046293202,1027973488,-1121978412,1036814117)+W(6,-1104816365,1034193475,-1148596400,-1107858514)+W(7,-1117927817,1034286113,1041009105,-1114981924);WS(1049012636,1037011386);
sum1=W(0,-1108102978,-1097922903,1049818257,1041216474)+W(1,1042768739,-1089977373,1052134241,-1106782690)+W(2,1036457352,-1083790961,1059747641,-1120768141)+W(3,-1105146600,1050515995,1062551839,975424142)+W(4,-1100621772,1053649082,-1088576433,1042971413)+W(5,-1100160944,1044221701,-1093385002,1047421135)+W(6,-1149100234,1020595485,-1108848982,-1142399358)+W(7,-1116535239,-1110188826,-1147628986,1034144007);sum2=W(0,-1130376652,-1109271051,-1098570547,1029552052)+W(1,-1109307779,1040605589,-1097221185,-1097745138)+W(2,998991648,-1117670218,-1087670872,-1101762859)+W(3,-1105231849,1068278024,1068017963,-1100990121)+W(4,-1124853008,-1099193318,-1103240593,-1094879980)+W(5,-1110904873,1035466738,1049832589,-1119653306)+W(6,1033926100,-1111928806,1018913792,-1099498770)+W(7,1012787248,1025845624,1035573068,1046656503);WS(-1099128120,1074104605);
sum1=W(0,1001695642,1031876531,-1106225286,1039516460)+W(1,-1114738061,1036082771,-1127447088,1037331996)+W(2,-1137881464,1049670772,-1114090766,1048871226)+W(3,1035838167,1045634202,-1084335000,1024672505)+W(4,1036976671,1039176783,-1092101927,-1111706306)+W(5,1043227732,1044499416,-1106295064,1040216275)+W(6,1024532056,-1115296143,-1108352670,1018355325)+W(7,1041576607,1036111714,-1103209586,-1129216251);sum2=W(0,-1125983803,1057121124,-1097673861,-1097055530)+W(1,1026289226,1048908439,-1081617292,-1105528539)+W(2,1003361806,1042597022,-1083990029,-1094090339)+W(3,1036989304,-1101738899,1066557847,1060807350)+W(4,-1121376018,-1101518001,1050089807,1045798092)+W(5,-1127516251,-1114490175,1021212715,1007168711)+W(6,999276462,1032222895,-1107462587,1021142275)+W(7,1020382491,-1111061815,1048167829,1024157832);WS(1043392312,-1114334171);
sum1=W(0,1041086874,1046571639,-1101297859,-1108043111)+W(1,1027676176,1051603231,-1100311555,1031499310)+W(2,1029494548,-1114765098,-1090719068,-1123479337)+W(3,1038182418,1063881062,-1092551191,1047470620)+W(4,1033375641,1036439434,-1093343060,1029157954)+W(5,1014428948,1039261900,-1095549099,-1113522785)+W(6,1016176348,1049353410,-1102133676,1032866554)+W(7,1036956537,1039119196,-1097401399,-1108903402);sum2=W(0,1032922039,-1110774431,1024080221,-1111786600)+W(1,1034144522,1041464609,1024001520,1038622987)+W(2,1035186417,-1089347840,-1102975683,-1098326560)+W(3,-1106146153,1063858171,1062496232,-1094555153)+W(4,995983013,-1103182741,-1104694448,-1110476474)+W(5,1014708981,-1105498679,1034761930,-1107944280)+W(6,-1118508182,1046443094,-1113235807,1045574278)+W(7,-1122673776,-1107403517,-1126790312,-1119406695);WS(1055141020,1060902337);
sum1=W(0,1034435725,1057965143,-1123568702,-1104499136)+W(1,-1133288704,1052483105,-1121795134,1006999415)+W(2,1026181508,1052696320,-1094115828,-1153162900)+W(3,1033934442,-1122504460,-1084201687,1029709087)+W(4,1030709219,1052884304,-1093347107,1036285529)+W(5,-1118188821,1049027177,-1096042081,-1155692311)+W(6,1027652318,1046782257,-1098441692,1013713298)+W(7,1035419593,1045790650,-1101051195,-1111952258);sum2=W(0,1043194323,-1070666261,-1098866335,-1101126135)+W(1,1017945729,-1075189642,-1106608294,1010301074)+W(2,992756489,1068575013,1051129947,-1107911121)+W(3,-1117717167,1076566585,1049134123,1046700061)+W(4,1023440269,1056539999,1047751107,1020103457)+W(5,-1108161809,-1098049115,-1097073139,1026363561)+W(6,1034607052,1036076910,1011007330,1035420194)+W(7,-1115924363,-1112346970,1016205049,-1137869730);WS(-1090579868,1070279725);
sum1=W(0,1032329895,1048430680,-1101560157,-1129281319)+W(1,-1102328821,1050349544,-1091335294,1012204235)+W(2,-1113203900,1052980239,1039656780,1033674783)+W(3,-1098061089,1057014372,-1084573078,-1115372202)+W(4,-1105344998,1057962188,-1103450436,-1108117804)+W(5,1034205973,1038273502,1043587871,-1111454739)+W(6,-1106552005,1046276062,-1098888483,-1115265901)+W(7,1041435478,1049777060,1002064136,-1109943484);sum2=W(0,987673807,1027892228,-1103141235,1005138532)+W(1,1036995374,-1102736131,1049007178,1028221332)+W(2,-1095509641,1034852634,-1090760003,-1123669832)+W(3,-1094252408,1059241808,1060311666,-1128511149)+W(4,-1119095571,-1103859919,-1129798465,1032914452)+W(5,-1103179232,1043446486,-1100012675,1006285508)+W(6,1040985329,-1109795439,1051746582,-1122773902)+W(7,-1114181285,1004807604,-1113144024,987177167);WS(1058381774,-1086956646);
sum1=W(0,1005434106,-1096145742,1046241393,1026532260)+W(1,-1149835360,-1100460324,1039571170,-1120107684)+W(2,1034370117,-1096424577,1054608457,-1107524072)+W(3,1036055789,1033532617,-1110152984,-1123297125)+W(4,1007595428,1049990129,-1100950084,1032832748)+W(5,-1173712576,1042033667,-1103984787,1041584782)+W(6,-1122685332,-1147483724,-1122634471,-1111048693)+W(7,-1119060568,1021597150,1016207588,1023439817);sum2=W(0,1073050559,1049113865,1048373410,-1123382260)+W(1,1069067455,1035642194,-1101089925,1035361564)+W(2,-1096535796,-1105600932,1050248373,-1105239942)+W(3,-1073893027,-1114871718,-1113393188,1000972215)+W(4,-1077684470,-1104998692,1015693919,-1112223483)+W(5,1038335059,1034875990,1032989733,987872957)+W(6,994568047,1004288083,1024635942,1016564448)+W(7,-1109196141,1019116562,1041247426,1019016937);WS(1051792028,1027146209);
sum1=W(0,-1173418992,-1096555104,1048715847,1037767898)+W(1,1031492470,-1099279313,1043543405,1032372106)+W(2,1030866682,-1102472206,1045948678,1031937048)+W(3,-1111745573,-1086728512,1048944276,1030986133)+W(4,1037975597,-1098029143,1053562136,1035090980)+W(5,1032231158,-1099704976,1041023999,1038793940)+W(6,1021051177,-1107704157,1031959404,1031982829)+W(7,1029296729,-1088435526,1046674105,1043937550);sum2=W(0,1076285256,-1071495861,-1089164092,1024798548)+W(1,1067013205,-1080654015,1044446905,-1130255717)+W(2,1054912747,-1092768710,-1089831336,-1111620633)+W(3,-1103468782,1053690657,1049463752,-1129289568)+W(4,-1082179927,1062196550,-1116071286,1022374674)+W(5,-1086354611,1059230433,1055604285,-1147177200)+W(6,-1086555076,1065208788,-1102169042,1008723412)+W(7,-1077304359,1069826015,1049830695,990531682);WS(-1116843232,1041538044);
sum1=W(0,1038718416,1050813118,-1091780513,-1107356403)+W(1,1041393778,1048646402,-1107072481,1032833522)+W(2,1023355030,1043671731,-1097953353,-1126022145)+W(3,1040958951,1037057641,-1088265503,-1185162751)+W(4,1040537034,1050123337,-1105750724,1038008293)+W(5,-1112360254,1052799074,-1091053114,-1123581176)+W(6,1043346413,1037436293,-1121572392,1033129910)+W(7,1047211822,1042212684,-1091261766,-1116284746);sum2=W(0,-1127892588,-1090048491,-1076486023,1071993665)+W(1,1025248710,-1124324076,-1080184847,1067215194)+W(2,-1127740272,-1092974499,-1080442855,1068762214)+W(3,-1114879615,1047668544,1048567939,1014309155)+W(4,-1125515678,1042122418,1066323214,-1079656754)+W(5,-1135605467,1052455522,1068938556,-1077318729)+W(6,1015277154,-1102075660,1066205534,-1083078137)+W(7,-1118452308,1052515578,1058048535,-1086246531);WS(1045082936,1047750074);
sum1=W(0,1017867382,1038967959,-1107005280,-1117189504)+W(1,-1105827232,1036533543,-1101431328,1000061951)+W(2,-1139557912,1048524561,1044741561,1034808454)+W(3,-1098507795,1057427781,-1099209723,-1102176472)+W(4,-1112138258,1057555836,-1103886606,-1102736460)+W(5,-1113781499,1044700722,-1117912777,-1102956733)+W(6,-1117154624,1037485187,-1108908881,-1113728179)+W(7,1024003356,1046059755,1024367918,-1108156515);sum2=W(0,1003184961,1024857236,-1114215978,1037587704)+W(1,971431442,-1109323954,1030818718,-1121823736)+W(2,-1131894760,1026446282,1031262679,1045339410)+W(3,-1133283297,-1105665514,1056963612,-1107079097)+W(4,984723076,-1116186208,1055283667,-1090072253)+W(5,1031831407,1024492508,975724297,-1102678968)+W(6,-1125590160,-1121629964,-1116339968,-1103014356)+W(7,1031681833,-1148808497,1026784592,-1123463096);WS(1059869006,1015916977);
sum1=W(0,-1111801867,-1103727218,1051877295,-1115491581)+W(1,1039164638,-1102716146,1051739903,-1106752078)+W(2,1023424768,-1089648586,1057614174,-1104830517)+W(3,-1118862224,-1092420393,1055627629,-1112797325)+W(4,-1114194639,1049092536,-1096079006,1038662167)+W(5,-1099094340,1052180160,1008315659,1030088557)+W(6,-1118811114,1032231232,-1121275805,-1131680577)+W(7,-1096321008,1046058153,1039975892,-1175801754);sum2=W(0,-1113427160,-1090644207,1034414883,1038986783)+W(1,-1104433368,-1091764889,-1120815960,-1135559136)+W(2,-1104169884,-1109333336,995253792,1033390214)+W(3,-1117600576,1065407690,1059846520,-1120264784)+W(4,-1102319880,-1098732665,1048874179,-1104270640)+W(5,1039627671,-1109931470,1008884504,1019376128)+W(6,-1097619580,1043714297,1021072320,-1111461786)+W(7,1047721667,1041133481,-1103318888,-1142244432);WS(1054131356,-1077482588);
sum1=W(0,-1100136045,-1101215881,1045307006,1047064142)+W(1,989703980,-1100083265,1039854844,-1120855287)+W(2,-1114161471,-1091699940,1051542530,1042850313)+W(3,-1117800461,-1088812180,1056393300,-1122501592)+W(4,1013262449,-1095974704,1053327664,-1118254671)+W(5,-1112319975,1033042241,1059113280,-1111473941)+W(6,1027862775,-1095224480,1049428707,-1119385054)+W(7,-1103330903,-1102789769,1055440053,-1109190398);sum2=W(0,-1098032416,1063396296,1043414797,-1093635160)+W(1,1055692800,1024719031,1032661901,1049215120)+W(2,-1101668743,1065491656,1058961916,-1090478816)+W(3,-1100435053,1073645059,1063424749,1050905898)+W(4,-1089098280,1060161647,-1096580753,-1135528507)+W(5,-1094416925,-1074198531,-1098776178,1042380471)+W(6,-1099202751,-1081296593,-1115458644,1032695397)+W(7,-1104551065,-1083400329,-1092624053,1054277265);WS(-1082679118,-1072338335);
sum1=W(0,-1126832308,-1092407662,1041636256,1032452512)+W(1,998650886,-1099976035,1035459839,-1118647007)+W(2,1029713605,-1098757312,1053507448,-1113994637)+W(3,1045660229,1049242330,-1097348797,1019901759)+W(4,-1125245511,1052609817,-1097111418,1026546307)+W(5,1001090478,1049104969,-1099322690,1041545965)+W(6,-1126242526,958956607,-1116731426,-1113342195)+W(7,-1128346278,-1170516592,1009511091,1027607012);sum2=W(0,-1069228184,-1099529380,-1112044089,-1144476451)+W(1,-1073602631,1043301860,1041147606,-1112019052)+W(2,1021776922,1054858487,-1119872164,1036271953)+W(3,1076866983,1044685536,-1106846135,1018899191)+W(4,1069809281,1062109344,1042271976,-1114284680)+W(5,-1101499289,-1097491140,1035368326,-1126672913)+W(6,1013617559,-1149319294,1025827813,-1112053703)+W(7,1036050969,-1113127688,-1115137330,-1146921887);WS(-1125906880,1029353026);
sum1=W(0,1052620124,-1082830235,1044570800,1033131793)+W(1,1040928385,-1087911853,1048894344,1031982257)+W(2,1053619569,-1088553290,1054767249,-1118254573)+W(3,1034478636,-1115166792,1052323270,1037418321)+W(4,-1149501032,-1104403058,-1096342700,1045103465)+W(5,1027228408,1046902211,-1092690897,1053685367)+W(6,1033816441,-1140598044,-1112660402,1032758420)+W(7,-1143379631,-1115398454,-1089842615,1056771243);sum2=W(0,1052242091,-1123374674,-1088438592,-1109756837)+W(1,-1105901664,1032004261,-1109896025,-1117902306)+W(2,1041713460,1057464262,-1106721416,-1106560728)+W(3,-1098081544,1055897675,1057898227,-1101499608)+W(4,-1101414896,-1108453649,1044097375,-1114554169)+W(5,-1140318759,-1099401944,1041656473,1042131382)+W(6,-1123485994,1039811869,1042751001,-1104786072)+W(7,-1108472633,-1092934450,1033994653,1048148308);WS(-1080878567,1068324028);
sum1=W(0,-1115471279,-1095139206,1057833304,1032811018)+W(1,1019310859,-1103458412,1049561152,-1118469827)+W(2,-1121098697,-1090917913,1058273109,-1107876783)+W(3,-1115193805,-1094785898,1054221326,-1109399058)+W(4,-1153442440,-1100131090,1050583410,-1121957752)+W(5,-1104713039,-1118370765,1048985266,-1109945243)+W(6,1023975060,-1102569730,1041261354,-1125987028)+W(7,-1094675607,1044057356,1045920684,-1144681671);sum2=W(0,-1122597644,1052263517,1084267296,1037076324)+W(1,1032420914,-1132353885,1077171750,1017945885)+W(2,-1109997244,-1113437764,-1076080701,1045994672)+W(3,1029919127,-1086124512,-1066836895,-1105598049)+W(4,-1129031901,-1134522929,-1073829589,-1115453382)+W(5,1025876905,-1137529969,-1128728545,1027437378)+W(6,-1121404056,1041285329,-1128683125,-1112127416)+W(7,1025649559,-1111439550,-1109934248,1032857588);WS(-1106960696,-1099012034);
sum1=W(0,-1114528403,-1099071342,1055554285,-1109121109)+W(1,-1119077260,-1099370430,1049964157,-1115766890)+W(2,-1143558020,-1089278443,1061104081,-1114965299)+W(3,-1119877760,-1086538844,1056629915,-1120868875)+W(4,-1109244232,1010994112,1049997315,1034547527)+W(5,-1096650748,1041376829,1042073805,-1114495407)+W(6,-1112604445,1042854492,1031563405,-1139584324)+W(7,-1100402892,1049345155,-1123516568,-1118254096);sum2=W(0,-1116593925,1027806287,1032648371,1024756439)+W(1,1028908115,-1136470458,1006654490,-1116529299)+W(2,999050165,1039840949,1052059722,-1107372324)+W(3,1037914955,-1122048333,1057985079,-1128153177)+W(4,-1106109711,1057135276,-1090440242,-1142966917)+W(5,-1105957739,-1105275062,-1131926605,-1123338691)+W(6,-1123834115,-1096566133,1018741845,1013415162)+W(7,-1113783754,-1105721601,-1124260101,1018182189);WS(-1103089976,1059868827);
sum1=W(0,1026631887,-1091300264,1056895190,1031003956)+W(1,1033737723,-1096562704,1050565142,-1140469197)+W(2,1034000797,-1087537316,1059766350,-1108911023)+W(3,-1130496915,-1094386976,1053939124,1032926090)+W(4,-1106694966,1044429902,-1108577640,-1120892680)+W(5,-1105866475,1045093007,-1109922270,1034482579)+W(6,-1106727101,1040636078,-1122075862,-1136817768)+W(7,-1098705919,1044615672,-1100982776,1045052014);sum2=W(0,-1114832682,1044376552,1052671036,-1084839384)+W(1,1038307608,-1101986459,-1094811671,-1076225566)+W(2,-1109268272,1025272345,-1106762472,-1074779618)+W(3,1031259614,-1112738770,1052706603,-1088390497)+W(4,-1136199018,1014008179,1040752903,1066038403)+W(5,-1118450441,1042085570,-1100877636,1071357616)+W(6,1025376385,-1110075404,1051973899,1068318141)+W(7,-1125957173,1027010884,1036345951,1050587817);WS(-1089897038,998399462);
sum1=W(0,-1100326508,-1114312802,1049930251,-1141222070)+W(1,-1099771006,-1109889234,1047140918,-1114407115)+W(2,-1103969415,-1092992143,1060325312,-1106384368)+W(3,1030998252,-1098209637,1062808044,1017922927)+W(4,-1111096702,-1116385180,-1128865717,1023432554)+W(5,-1129527451,-1096464604,1048691588,-1125954964)+W(6,-1115021151,-1111889198,-1137813989,-1121716413)+W(7,-1124899748,-1109224641,1043572929,1020452535);sum2=W(0,-1094975511,-1113696880,1023473326,1029862812)+W(1,-1089233591,1032844980,1036803698,-1117299445)+W(2,-1089977002,1066397244,-1129026618,1025970568)+W(3,1033778332,1037917830,-1104280508,1031377784)+W(4,1006981461,1039504138,1024702770,-1122944997)+W(5,-1137053176,1032622380,-1121975322,1022461928)+W(6,-1125132764,1021506052,974010432,-1130740686)+W(7,979684320,-1119563165,-1138205260,1024270227);WS(-1096120220,-1099720911);
sum1=W(0,1052677544,-1105594052,-1101878153,990296621)+W(1,1027883172,1050583742,-1120505890,1026529890)+W(2,1046184634,1030711656,-1094174707,1039246623)+W(3,1036941212,1050761182,-1087347673,1031039363)+W(4,1037786724,1044997418,-1091299260,1038193547)+W(5,1039372749,1051859318,-1092171165,1036921611)+W(6,992842790,1041579690,-1105854769,-1115076484)+W(7,1040590154,1052858474,-1087724293,1007468831);sum2=W(0,1040381409,1023777345,-1110031849,1022623295)+W(1,-1131846701,-1095435966,-1146822820,-1096899181)+W(2,1030695069,-1111411494,-1089001391,1049343346)+W(3,1015259161,-1085163747,-1074171332,-1107180310)+W(4,1026868853,-1100600319,-1078760233,1043071461)+W(5,-1164136976,1052695808,1048168469,1020495459)+W(6,-1121164685,1041440525,1074132102,1017314953)+W(7,-1109936403,1051545155,1072577306,1050115198);WS(-1080112807,-1111145054);
sum1=W(0,-1103297132,1049824404,-1133975251,1026400021)+W(1,-1106341774,1049617192,-1122989109,1042898005)+W(2,-1098278655,1059552348,-1086286580,1041608840)+W(3,1024154699,1031972225,-1137351813,-1145221295)+W(4,1037514093,-1085661228,1056970252,-1102084285)+W(5,1034961350,-1097823136,992708574,1041904442)+W(6,-1125780682,-1114326813,1021582000,1038246926)+W(7,-1109009483,-1119831648,1040424089,1042525799);sum2=W(0,1041258750,989910477,-1134607603,-1109794979)+W(1,-1109734283,-1100922013,1016064722,1041809078)+W(2,-1123542769,-1096844113,1041392492,-1126381362)+W(3,-1113561957,1051742866,1057819912,982123162)+W(4,-1110564237,-1100235579,1047439582,-1119465765)+W(5,1026811493,-1105813951,-1113868277,1026735929)+W(6,-1130694514,-1151284621,-1118083589,1019553626)+W(7,1024057869,-1136706867,-1114600003,-1114678252);WS(1043409720,-1105036943);
sum1=W(0,1040191749,-1096303173,-1115184605,1041655059)+W(1,1033970558,-1095924673,1041748910,1041917006)+W(2,1042494496,-1093807736,1044442592,-1160531625)+W(3,1046767380,-1092831585,1042876074,1039311757)+W(4,972615552,-1096756208,-1140612185,1020654492)+W(5,1032778168,-1126846855,1018241414,1043700571)+W(6,1032217109,-1115229280,1027878365,1034107952)+W(7,1032356247,-1098580285,1034858676,1036396440);sum2=W(0,1027808259,-1139047739,986751832,-1095774205)+W(1,1010119787,1043340308,1026247831,-1093511024)+W(2,-1111510504,-1106790738,1065364148,-1089533357)+W(3,-1113418759,-1096910874,1040723354,1053173071)+W(4,1032132185,1040059331,1038861011,-1106558855)+W(5,-1121052855,-1115460243,-1113647147,1027584935)+W(6,1014515195,1017581734,1041604470,-1121443175)+W(7,1010692603,-1120741339,-1135975307,1014681515);WS(1035857520,1029952289);
sum1=W(0,-1143077795,1037051011,-1110400621,-1121149466)+W(1,-1105351783,1029971495,-1106469910,1043652126)+W(2,-1113811952,1049064844,-1094483622,1027875988)+W(3,-1106526780,1035603988,1058276716,1035104701)+W(4,1035289215,-1083894414,1056346487,-1114346217)+W(5,999420801,-1098557596,1050633420,-1123554317)+W(6,-1129002434,-1111645039,1042325343,-1130799743)+W(7,-1113970285,-1130790920,1026109447,1025377311);sum2=W(0,-1118517607,1026484093,1039465846,1008581907)+W(1,-1101077931,1046485772,1030900361,-1114630284)+W(2,1029148161,-1098019518,1048118782,-1106945018)+W(3,-1087996420,1071267691,1064954318,-1097625455)+W(4,1047526016,-1082674625,-1084489705,-1156379726)+W(5,-1108756119,1032470282,-1118487613,1024110641)+W(6,1038718292,-1106613565,-1112021711,1020048570)+W(7,1024464693,-1113199029,-1120012731,1036291722);WS(1058189134,1034857672);
sum1=W(0,-1171748679,1031241360,-1100969760,987174985)+W(1,-1105475825,1044072484,-1094075536,1045893176)+W(2,-1097172873,1057114388,-1082247827,1042860595)+W(3,-1108837708,1051374554,1060030327,1031954257)+W(4,1038034707,-1083662360,1058651386,-1120638978)+W(5,-1131134898,-1099379283,1046921459,-1137288661)+W(6,-1113151849,-1121036423,1041721673,1037681908)+W(7,-1119273967,1018101850,1036514264,1029972391);sum2=W(0,1003810984,1020569783,-1128982694,1043745048)+W(1,1036204547,-1114489126,-1099380876,-1104004872)+W(2,-1101998989,-1121260135,-1101918458,-1104165612)+W(3,1041029203,1052640914,1059611184,-1121067579)+W(4,-1098215637,1059150102,1040381797,-1100369008)+W(5,1044393168,-1098121773,-1094102036,1032515174)+W(6,-1110527635,1037147118,1028175839,-1114899975)+W(7,1027560485,-1110248773,-1113935142,1000033398);WS(-1107450480,1040804833);
sum1=W(0,1040192716,1040473489,-1095196747,-1124855402)+W(1,1022226221,1047969017,-1098407451,1020416041)+W(2,1002013395,1044185574,-1087290490,-1160070647)+W(3,-1117682794,1060667554,-1089168888,1045737613)+W(4,1001040843,1057909434,-1111951852,-1101676720)+W(5,1000424795,1049088596,-1119291421,-1103624738)+W(6,-1120982404,1038016429,1031577591,-1104451167)+W(7,1025306833,1042416864,-1112956481,-1115902938);sum2=W(0,1014727333,-1124633329,1026257754,-1111611661)+W(1,-1117243126,-1107065949,-1111801245,-1136702760)+W(2,1029406572,1041729284,-1084100906,-1103677442)+W(3,1027900147,-1094200388,1052541581,1050798725)+W(4,-1112527674,-1104959017,1070744988,-1105828213)+W(5,-1114664521,1040214496,-1111707080,-1111536822)+W(6,-1111634336,1005029260,-1127513012,-1106506739)+W(7,-1107116047,1049039902,-1107038609,-1140667375);WS(-1113867888,1064515135);
sum1=W(0,-1113562537,1048061265,1011269086,-1105945126)+W(1,-1107046062,1043460993,-1098944190,-1148623547)+W(2,-1103978495,1060048584,-1107431310,-1111558073)+W(3,-1098739202,1062873548,1045822761,-1114838028)+W(4,-1122423580,-1119786749,1025265092,-1101841139)+W(5,1019693149,1023528257,-1112998912,-1117915947)+W(6,-1116789880,-1106657727,-1142662356,-1106868487)+W(7,1020558520,-1137576074,-1104660585,-1122252061);sum2=W(0,-1145158406,1022878354,-1111624996,1010204019)+W(1,1012385731,-1129472106,1015658802,-1123973089)+W(2,1016118130,1044961455,1040055751,-1157676569)+W(3,1024197601,1049544336,1057430996,1022031298)+W(4,-1112179804,1030346877,-1114498280,-1124728962)+W(5,-1119519161,-1131221354,1020564842,1023003938)+W(6,-1127326042,-1095482557,-1112131584,-1121117277)+W(7,-1113792718,-1093377057,1019749938,-1141925830);WS(1051333020,-1087054195);
sum1=W(0,-1112042433,-1104387605,1052246829,-1113527444)+W(1,1019002067,-1096771599,1048899277,-1098301717)+W(2,-1115058903,-1102529947,1054136106,-1095193948)+W(3,1046618143,-1093976551,1044227957,1044013586)+W(4,-1107874438,-1089735051,1060328029,-1107288943)+W(5,-1148774132,-1129150690,1046377228,1038700845)+W(6,1036768028,-1101876091,1045160291,1024370318)+W(7,-1154881470,-1098135714,1045432325,1019966234);sum2=W(0,-1114066012,1041392892,1044719218,-1097547793)+W(1,1029900262,-1112610934,1046575198,-1095644935)+W(2,-1114806697,1041587346,1050162797,-1102972970)+W(3,-1110038644,1025557898,1055420600,-1095936036)+W(4,1036646832,1055783298,-1099287148,1028020818)+W(5,-1110070018,-1102485451,-1100701871,-1113902766)+W(6,1020625547,988088600,1033323822,-1135974783)+W(7,987867800,1039502616,-1119304428,1018696751);WS(-1120103648,-1090070191);
sum1=W(0,-1117418940,1049030490,-1112262737,-1114427969)+W(1,1024592611,1050801054,-1094705236,1032013281)+W(2,1040968250,-1111205267,1042055990,-1110419822)+W(3,1049918615,-1116228463,-1085341341,1047944497)+W(4,1034410595,1050512309,-1106227665,-1132367051)+W(5,1035134604,-1102511675,1036298997,1025392341)+W(6,-1119948353,1034763283,-1138448657,-1111046724)+W(7,-1144523437,1039656998,-1110564136,-1120201127);sum2=W(0,-1122606938,1046354401,-1124762815,-1118515993)+W(1,-1141997982,1040228902,-1102583710,1036845124)+W(2,1027805544,-1143835982,1052785838,-1106443071)+W(3,-1120462650,1061896257,1059397472,1043676745)+W(4,-1100560083,-1080731069,-1120768779,995709275)+W(5,-1105726471,-1098049024,-1126645315,-1128858827)+W(6,1025575588,1026943708,1011421951,-1112152255)+W(7,-1113668318,1032253740,-1122685018,-1127110207);WS(1060158670,1068766623);
sum1=W(0,-1116432453,1056712636,-1087151539,1040295867)+W(1,-1131098839,1049784895,-1102593034,1033948341)+W(2,-1099753724,1057908127,-1089291740,1031077093)+W(3,1034945056,1044163070,-1094800699,1027113355)+W(4,-1122123599,1028198895,1036808107,-1132674679)+W(5,1040823512,-1122504371,-1120242995,-1117547229)+W(6,1040184285,-1123329903,-1127465369,1040274980)+W(7,1050332416,-1096645803,-1132187055,-1137741501);sum2=W(0,1036379663,-1098232449,-1128107780,-1120677803)+W(1,-1108907739,1058983203,1035811659,-1120240179)+W(2,1070189048,1016986873,1040144345,1029686139)+W(3,1073213180,1047923452,-1105399966,-1109097268)+W(4,1065321765,1033582270,-1110681209,1041308319)+W(5,-1076673488,1031365639,1039880527,-1109042515)+W(6,-1079893128,1038048757,-1116001167,1034493417)+W(7,-1072585926,-1107019906,1018297481,-1131123922);WS(-1112459888,1031046963);
sum1=W(0,-1112719265,-1128634346,1043326546,-1115081924)+W(1,-1129483154,-1120462421,-1103778738,-1114915140)+W(2,-1103727283,-1112785958,1050524372,-1104237825)+W(3,-1091575740,1056781779,1067939282,-1096588493)+W(4,-1104335643,-1153409228,1048587330,-1108534894)+W(5,-1155155940,-1108013960,-1132710977,-1114726045)+W(6,-1114094348,-1118230989,-1109505653,991235804)+W(7,-1105426861,1027667442,1036777787,-1111746006);sum2=W(0,-1119086167,1037241732,-1114652243,-1131518324)+W(1,1013020612,-1129818230,1028260797,-1115730540)+W(2,-1141008560,1029187991,-1112264831,1036245214)+W(3,-1108719150,-1074141953,1072760747,1034705438)+W(4,1023891147,1019083994,1042535682,-1119172530)+W(5,-1145112744,-1124211508,-1131878972,-1133917220)+W(6,1018251990,-1122886966,1037493286,-1114007324)+W(7,-1116478859,1027168441,-1129254230,1018465006);WS(-1086783566,-1086791567);
sum1=W(0,-1115195632,-1095708330,-1123676804,1041725033)+W(1,-1153026662,-1093442522,1018199561,-1121101892)+W(2,-1134496297,-1098161001,1037878573,1034570216)+W(3,-1108787789,1044632085,1064261167,-1103584185)+W(4,-1119803561,-1091375169,1057417647,-1108866704)+W(5,-1145121243,-1107384199,1052226946,-1122033784)+W(6,-1131708777,-1100078210,1046948682,-1117964907)+W(7,-1110064394,-1104664012,1047330733,1022321300);sum2=W(0,1031515378,-1077397139,-1134939312,-1112896962)+W(1,-1121810184,-1079753374,-1097085111,1035985281)+W(2,1010081392,1044674665,1052841311,-1105060263)+W(3,-1119765868,1073378801,1007836336,1031953140)+W(4,1035546479,1056367001,1044809025,1022446080)+W(5,-1106495935,-1109376902,-1118570548,1031289566)+W(6,1028378344,1035615024,992033726,1032016077)+W(7,1003402623,-1118889676,1010750288,-1150317246);WS(-1096711324,-1080143969);
sum1=W(0,-1135181951,-1095339398,1050582337,1026786373)+W(1,1025399430,-1094144146,1049483953,-1123204644)+W(2,1033906501,-1093853897,1045129706,1006467326)+W(3,1041786535,-1089314149,1046728732,1031608549)+W(4,-1133559462,-1089126233,1045641984,-1135165794)+W(5,1003671004,-1110956839,1051092970,1017185520)+W(6,-1123695637,-1129083412,1049638101,996324016)+W(7,-1105366874,-1113909272,1057307443,1009923752);sum2=W(0,1023911567,-1108118447,1044892126,-1112738860)+W(1,1004932796,-1134375038,-1138359022,1020475455)+W(2,-1119124867,1035251904,1063133445,-1102926770)+W(3,1022775023,1037995724,1074655410,1047698054)+W(4,1011639102,1050162042,1070062472,-1113839430)+W(5,1036397588,1037707684,-1083132698,-1117927031)+W(6,999444348,-1111062570,-1073510095,1017195567)+W(7,-1106309084,-1101285996,-1073687480,1041743674);WS(-1089880270,1068594400);
sum1=W(0,-1114467040,-1104513741,1050219169,-1118490053)+W(1,1023170830,-1091458130,1042545281,-1120682309)+W(2,1036273894,1034367029,1048674674,1031296832)+W(3,-1107800974,-1100997781,1042739212,-1110241363)+W(4,1029867434,-1095286649,1053624831,1034289100)+W(5,-1106779367,1047811540,1034908007,-1107012174)+W(6,1024593089,-1096228817,1034674708,1021221591)+W(7,-1110449433,-1109179032,1049808694,-1126204757);sum2=W(0,1030004067,-1133064657,1024174065,-1119836251)+W(1,-1117028113,-1134091777,-1113615539,1025775761)+W(2,-1105887481,1045929484,1032698350,-1118489229)+W(3,-1066126465,1081917443,-1097201480,1041573100)+W(4,-1104777348,1043726141,1033613382,-1124268877)+W(5,-1122550707,1028310407,-1107697461,1030764051)+W(6,-1130918117,1016764395,1029778305,-1116797441)+W(7,1023720579,-1116064873,1018371831,1018350967);WS(1067475431,-1126058166);
sum1=W(0,-1108052732,-1097851361,1049362324,1040199303)+W(1,1043040440,-1108210069,1048929252,-1109622414)+W(2,1048922396,-1084429932,1054104112,1041203782)+W(3,-1097574342,1055911149,1047147106,-1104274751)+W(4,-1119673025,1041902328,-1085779789,1047880876)+W(5,-1101774749,1035827603,1049622021,-1116198608)+W(6,1019400344,-1115594513,1019477630,-1107876353)+W(7,1007801026,-1107003538,1037086373,1036701569);sum2=W(0,1013753738,1020731454,-1120697178,1009873360)+W(1,-1113150555,1046742995,1034035253,-1099358283)+W(2,1015248850,1045156685,-1094710566,1039470065)+W(3,1042650722,-1104352239,-1128318417,1046693145)+W(4,1040818978,-1089864705,1045040370,1036008061)+W(5,-1105652199,1045331461,1025091411,1030627793)+W(6,1033430289,-1109224259,-1106535436,1017876415)+W(7,-1120377801,1016214593,1019751894,-1132110931);WS(1060496974,-1099362699);
sum1=W(0,1054706808,-1109706041,-1098091909,-1129324363)+W(1,1036662868,1041317773,-1123237413,1015757258)+W(2,1045895019,1051554925,-1091928498,1021341985)+W(3,1033303646,1049334366,-1083798889,-1112852963)+W(4,1044095763,1051166813,-1095315343,1041804248)+W(5,-1130190200,1053590462,-1087007295,-1127492145)+W(6,1035564779,1049285205,-1097088265,1039262630)+W(7,1040746168,1055551482,-1094550458,-1114905285);sum2=W(0,-1073385920,1077926840,1032559783,-1094451238)+W(1,-1084887580,1058818874,-1089669880,-1121878040)+W(2,-1083140914,1060159151,1045764296,-1173171215)+W(3,-1081800202,1074845707,1059775011,-1120435570)+W(4,-1085954594,1061906872,-1103860568,-1115590029)+W(5,1037413129,-1084431515,-1094536545,1053315192)+W(6,-1096433065,-1126824848,-1133232881,-1107838893)+W(7,1054210787,-1087315344,-1099186518,1052978812);WS(-1078369703,1041267413);
sum1=W(0,1024386586,1041630887,-1102607056,1016693023)+W(1,-1098405416,-1112635974,1051293608,1018393854)+W(2,1044040033,-1132435208,-1094040968,1046099151)+W(3,-1098286219,1041292515,1052507157,-1095618428)+W(4,-1130684104,-1091497929,1056853585,1018959206)+W(5,1045750173,1016159377,-1105775474,-1117949682)+W(6,-1098338270,-1139597330,1049412460,-1118540325)+W(7,1041584973,-1101611546,1026100205,1040982949);sum2=W(0,1035615459,-1097925659,1043665288,1020457849)+W(1,1028814353,1038714809,1033337220,-1103657321)+W(2,1062855981,-1077657685,1051048913,-1109823715)+W(3,1052250964,-1101970047,-1113114333,1058024935)+W(4,1056109526,-1098468896,-1085664062,1056999181)+W(5,-1106019250,-1114182260,1040975429,-1105846491)+W(6,1048995011,-1104046747,-1109605260,1042595027)+W(7,-1115640692,-1130122971,1034778788,-1112374505);WS(1049151900,-1114127847);
sum1=W(0,1050216581,1044969414,-1106856243,-1099359923)+W(1,1000015204,1047621718,-1112471205,-1148711507)+W(2,-1136218178,1057314961,-1091938023,-1133921207)+W(3,1023136961,1055877843,-1092033343,-1112054390)+W(4,-1130455775,1054358666,-1099719178,1034273823)+W(5,-1133465094,1052966059,-1089783713,-1122838974)+W(6,-1160090192,1045850836,-1099053307,1019980258)+W(7,1035991733,1052491071,-1087984664,-1112322824);sum2=W(0,-1105478410,1011113448,1068049752,-1082501551)+W(1,1039552519,1050864081,-1103020148,1059003564)+W(2,-1131405058,-1125310098,1066695202,-1098156272)+W(3,-1099466970,1043215106,1074596924,1039344435)+W(4,1049027924,1034334973,1067601936,-1099880092)+W(5,-1115050596,-1095883745,-1084539788,-1107282542)+W(6,-1129231446,1036178144,-1075514015,-1097076855)+W(7,1049583286,-1088635155,-1074115054,1042018058);WS(-1081332839,-1093454830);
sum1=W(0,-1109709318,1035356975,1039420520,-1111308088)+W(1,-1104916884,1037116623,-1122158672,1014687039)+W(2,-1108177419,-1125155242,1053028347,-1112931654)+W(3,-1117212646,1030327966,-1104761999,1020526050)+W(4,-1119705461,1050241163,1032136206,-1119448076)+W(5,1032417267,-1103907222,-1115200780,-1112611266)+W(6,-1118748528,1046095669,-1115609017,-1136487898)+W(7,987327371,1033262333,1029855614,-1104533373);sum2=W(0,1013207527,-1118344664,-1124997045,1036829905)+W(1,-1127355075,1028266047,-1117884424,1016171285)+W(2,-1103159789,1043690369,-1116887196,1024917624)+W(3,1040955478,1051132935,1047094008,1041601336)+W(4,1008876024,-1108842627,1057384051,-1127506713)+W(5,-1116686760,1041402295,-1100609336,1033786361)+W(6,1035764738,-1105537330,-1098518151,-1114313206)+W(7,-1154118338,-1128237045,-1089828796,-1102385561);WS(1063446990,1030048893);
sum1=W(0,-1131562670,1043069042,-1108681470,-1108650254)+W(1,-1099483503,1049571969,-1106599551,-1106453175)+W(2,-1106193120,1061428532,-1097709592,1008661917)+W(3,-1102405700,1053095529,1046689338,-1102088711)+W(4,1021119810,-1115069793,1029025472,-1123233168)+W(5,-1113568905,-1119868742,1006738196,-1104754348)+W(6,1009340592,1027160065,-1120287391,-1136963210)+W(7,1030255032,1043118346,-1111789333,-1114502129);sum2=W(0,1012371361,1017109065,-1110016822,-1103671135)+W(1,-1149491589,-1115161102,-1109821790,-1097972516)+W(2,1023756477,1012418345,1060485172,-1094449842)+W(3,-1165255819,-1111308586,1031379047,1049769129)+W(4,-1111467932,1015942947,1046805034,999148403)+W(5,1019335917,-1106016138,-1114576028,1022790203)+W(6,-1140694601,1015823021,1024897044,1032463998)+W(7,1010513313,1026481588,-1114618076,-1146831635);WS(1060385486,1040268319);
sum1=W(0,-1115333181,-1105770459,1048230464,1022495614)+W(1,-1113839600,-1104706211,-1122113023,-1115044751)+W(2,1026945989,-1085502934,1051932092,997701279)+W(3,1041834949,-1112644646,1065603891,1044329112)+W(4,-1100015113,-1102865873,-1105250533,1038196649)+W(5,1010458454,-1112283012,1054415097,-1113673817)+W(6,-1113704543,-1108020290,-1122402466,-1105082025)+W(7,-1110169699,-1115522389,1046973419,-1115640050);sum2=W(0,-1115664423,1041813775,-1142717933,-1120925434)+W(1,-1122287706,1041645390,-1094011677,-1119842210)+W(2,1044568139,-1087138046,-1124627987,-1120985148)+W(3,-1099350461,1067461852,1027339570,-1113918825)+W(4,-1102715015,-1116572542,1045144111,-1100833175)+W(5,1042022920,-1109622665,1054026149,-1101147879)+W(6,1031291077,-1113357449,-1122353792,-1112018489)+W(7,1032474264,-1110133469,1047364150,-1109170005);WS(1049043868,1050086952);
sum1=W(0,-1127858130,-1091279607,1054362490,1028884238)+W(1,1025810768,-1101354119,1044465651,1022883995)+W(2,1034666762,-1089232423,1050465752,1032068165)+W(3,989092984,-1092016019,1058690160,1005443958)+W(4,-1115481017,-1089729669,1053482909,1007092039)+W(5,-1119959429,-1104525366,1051092259,-1149438996)+W(6,1012364567,-1121438163,1019953121,-1137072337)+W(7,-1097661520,-1160888088,1051219071,1017307814);sum2=W(0,1030282550,-1099759289,1070065566,-1078832473)+W(1,1012065197,1050936278,1068820850,-1076346523)+W(2,1049708534,1018991152,1068572253,-1075628240)+W(3,-1101566471,1050588571,1075164582,-1072955990)+W(4,1043525707,-1112383125,1046261639,-1093459475)+W(5,1038111746,-1121285468,1053555382,-1088795804)+W(6,1040589253,1039884984,1040055978,-1099780818)+W(7,-1106531005,-1113841779,1058828770,-1090423367);WS(-1083655502,1074535575);
sum1=W(0,973651072,-1100106921,1049212555,-1122472503)+W(1,1028862937,-1096173461,1052529147,996549482)+W(2,1029517469,-1088250868,1057957824,-1111380529)+W(3,-1111330742,-1101351113,1060855844,-1125410415)+W(4,1043404639,-1092528244,1050267538,-1109626381)+W(5,-1105397947,1034877328,-1104065896,-1122247818)+W(6,-1129726574,-1113904430,1041335934,-1108333759)+W(7,-1099887737,-1118418050,1047916353,1037233742);sum2=W(0,1037582341,-1116649305,-1107051108,1040538112)+W(1,1032149251,-1112916551,1041643977,-1112067691)+W(2,-1135487115,1044443302,1030763641,1036263743)+W(3,-1107247151,-1117703407,1053360182,-1115814520)+W(4,1053968825,1049963138,-1087331905,1035849297)+W(5,-1096732175,1042101117,-1089009482,-1104153316)+W(6,1034930229,1046616621,-1110671517,-1104877620)+W(7,-1094249638,-1127010106,1059951262,-1116847106);WS(-1132786560,1056578758);
sum1=W(0,1031072232,1043718831,-1098888378,-1123786893)+W(1,1019453021,1050053971,-1104586611,1030360908)+W(2,-1112153353,1057505465,-1090760605,-1123598824)+W(3,-1127115205,1049535379,-1081773448,1035671447)+W(4,-1153314582,1052394474,-1106021324,1044649456)+W(5,-1105591705,1045418390,-1120283669,-1105554848)+W(6,986346381,1044283028,1036365944,1033186457)+W(7,1024604121,1048806335,-1103287167,-1108912601);sum2=W(0,1040658557,1011638864,1041865287,-1109113498)+W(1,-1106354313,1020064744,-1103147627,1033931950)+W(2,1027144364,1049840877,1026998340,-1120927100)+W(3,-1103628435,1050147177,1053587315,-1102211113)+W(4,-1123462592,-1117174472,-1118058864,1033328738)+W(5,-1130705048,-1105120318,1036775410,-1101351534)+W(6,-1126068784,-1113970774,-1104140895,1028877580)+W(7,1016031184,-1135769248,1030416564,-1112076066);WS(1062711758,-1109562142);
sum1=W(0,-1107075140,-1100622401,1053288051,1017596397)+W(1,-1125545776,-1104747337,1049612355,1007433175)+W(2,-1121788380,-1103229831,1059638178,-1120034657)+W(3,-1112684886,-1083301774,1048337697,-1098025711)+W(4,-1128625782,1050510715,1052952654,-1112854653)+W(5,-1102890883,-1097610180,1051307580,-1108240645)+W(6,-1129119788,-1109077454,1041285742,1022176121)+W(7,-1102110160,1030737729,1049115768,1020667959);sum2=W(0,1022257834,977550902,-1113927342,1036504102)+W(1,1033804876,-1105772859,1042844173,-1107093105)+W(2,1033963400,-1098748483,-1096777339,1028160469)+W(3,-1113268759,1063293804,1059312088,-1089861840)+W(4,-1123922685,-1090033704,-1134320563,-1101525036)+W(5,1029999681,1051039483,1037687330,1017532722)+W(6,1015463858,-1104977553,1024487701,-1122996995)+W(7,-1125618402,1022914778,1004875175,-1116068477);WS(1046002488,-1083997249);
sum1=W(0,-1116203964,-1099156844,1050076828,1025075217)+W(1,1044431961,1028498222,1049400252,1035032656)+W(2,1041235242,-1096363997,1050263757,1032516798)+W(3,1046371486,-1079124621,1020370202,1050189128)+W(4,-1106267745,-1088685662,1048790666,1042510329)+W(5,-1117705943,-1103556299,1053355933,1039724554)+W(6,-1122870401,999993136,1034829570,1027729159)+W(7,-1109240562,-1106798659,1037276039,1037249299);sum2=W(0,-1094982381,1041875660,1017839086,1045890174)+W(1,1024745423,-1091311273,1044409386,-1107764806)+W(2,-1097113645,1042706326,974632891,1048260200)+W(3,1017043870,-1148119319,1061393923,-1118443235)+W(4,1052555320,-1098101314,1043955676,-1097368628)+W(5,-1107563793,1010824956,-1098402228,1041238578)+W(6,1049262968,-1094774489,1042935118,-1116185663)+W(7,-1118735987,1030619863,-1094515595,1042214090);WS(-1083255246,-1075588436);
sum1=W(0,-1154522904,1026375684,-1099839750,1037990411)+W(1,-1106371438,1036249778,-1113752075,-1119606102)+W(2,-1105464695,1056687627,-1092436626,1043935324)+W(3,1036086422,-1097055709,1050924256,1036476796)+W(4,1023783355,-1088556578,1056650964,-1111337285)+W(5,-1127243930,-1108055408,1045926824,-1110940389)+W(6,1030176790,-1105944807,1039385437,-1124332025)+W(7,1031412139,-1123388097,1041066449,1021333175);sum2=W(0,-1117330831,1032531181,1043756688,1060766869)+W(1,1023708058,-1114369361,1031926890,1067300065)+W(2,-1133288218,1017487862,-1104593512,-1105945514)+W(3,-1122435213,1047518334,1043258354,-1075696003)+W(4,-1139180683,-1122916014,-1096895795,-1102393264)+W(5,1020252429,1027012545,1049767697,-1106946489)+W(6,1025188082,-1103557501,1019544307,1020047431)+W(7,-1109968059,1046855474,-1112657711,-1113285900);WS(1056055196,1023945849);
sum1=W(0,-1104545849,1036175954,1032040419,-1111539988)+W(1,-1139517988,-1138851412,1009002268,1026875367)+W(2,-1101013315,1048468083,1040659763,-1104005681)+W(3,-1136100212,-1097789539,1059870683,-1112873620)+W(4,-1148373856,-1096999890,1039368714,-1135793772)+W(5,1013350648,-1097071058,1053644410,-1132670698)+W(6,-1120654743,995622088,-1122818538,1028030253)+W(7,-1108930702,-1128233700,1033002810,-1133516850);sum2=W(0,1033182461,-1110992702,1011638125,-1116812221)+W(1,-1135790885,1041801313,976542168,-1135785781)+W(2,1036058972,-1115959119,-1106760241,1013579453)+W(3,-1145806187,-1083556559,-1068720208,1034110873)+W(4,1026470367,1047402951,1080067579,1048786168)+W(5,-1125994579,1026458945,1043021822,-1124564059)+W(6,-1123856921,1021989349,-1118809257,-1115658442)+W(7,-1152817846,1029289545,1027196491,-1110636256);WS(1047050040,1036867972);
sum1=W(0,1031952202,1041031945,-1098508279,-1117663192)+W(1,1040033213,1050476745,-1097704487,1033331580)+W(2,1049413776,1016870010,-1091275871,1012948685)+W(3,1052329098,1054273441,-1087382286,1043041286)+W(4,-1134253939,1041748879,-1095309386,-1131302504)+W(5,1023712847,1035493153,-1117526273,-1125396951)+W(6,-1129317744,1041656495,-1112254893,-1153578470)+W(7,1023414180,1041394937,-1108492595,-1112644847);sum2=W(0,-1120609508,-1138324119,-1110367912,1021280635)+W(1,-1098653081,1042859622,1038385587,1026624912)+W(2,-1074671298,1072071026,1026263792,1026288466)+W(3,-1081276780,1068070176,-1107049493,-1122098825)+W(4,-1097107702,1044485226,1024907208,1040255596)+W(5,-1110118090,1040658983,-1122488627,-1152233050)+W(6,-1137118351,-1118978815,1038809437,-1126727249)+W(7,-1119823807,1035453187,-1111098449,1006813455);WS(1047287096,1059538103);
sum1=W(0,1030804480,1034749929,-1102474905,1013951379)+W(1,-1111595219,1051408038,-1094490621,1039425378)+W(2,-1123153834,1049213285,-1099609086,-1112788128)+W(3,-1098057279,1057344539,1048597242,-1098419769)+W(4,1007980582,1048793645,-1094890059,-1118093753)+W(5,1018775223,-1106759404,1046324795,-1108341356)+W(6,1036089754,-1115115061,1003815995,-1120388747)+W(7,1030691489,1033654600,-1126686757,-1135294247);sum2=W(0,-1112864979,1024004698,1034996841,1004307827)+W(1,1034721747,-1109416755,1041661735,-1116757818)+W(2,-1108077379,988806988,1041642045,1037366938)+W(3,1023366533,1058238498,1008174217,-1107547239)+W(4,1021246669,-1115279539,-1122858630,-1108868659)+W(5,1032508120,1041332549,-1089151778,-1128614293)+W(6,-1113986367,1033457886,-1130797677,-1130732717)+W(7,-1153257254,1018109285,-1111548255,-1122125438);WS(1066216871,-1084582294);
sum1=W(0,1009745022,-1095963722,1050775177,1027534757)+W(1,1023325836,-1096473834,1046303345,-1126933960)+W(2,1034246149,-1087129751,1057767679,-1118146623)+W(3,-1103455511,-1142570129,1064400323,-1103828265)+W(4,1025953385,-1094684497,1038452388,1018950609)+W(5,-1105242559,-1107829831,992534739,1030437560)+W(6,988118663,-1107520037,1025316967,1020674901)+W(7,-1107601837,-1117719279,1044853309,1033139589);sum2=W(0,-1127013105,1031626404,1029958550,1017794797)+W(1,1018526115,-1117975133,-1113082476,1023300847)+W(2,-1123587641,1062148372,1035325186,-1145491637)+W(3,1052346460,1074624908,-1130733653,1041942663)+W(4,-1098654594,-1090512380,1046581721,-1113152926)+W(5,1029804743,-1070854231,-1113725416,-1139181075)+W(6,-1118240305,-1095518794,1031776819,-1120299385)+W(7,1030491706,1041467716,-1115594754,-1142763637);WS(1033725552,-1082653885);
sum1=W(0,1027658456,-1091894661,1054730080,1024810077)+W(1,1033791775,-1094613753,1052727904,1020875129)+W(2,1038169633,-1085886368,1060322284,-1114253244)+W(3,-1130834725,-1094605577,1054915405,1021660859)+W(4,-1105755912,1049096200,-1115316932,1010914050)+W(5,-1107114253,1038006563,-1113871235,1032412472)+W(6,-1106878767,1040399888,-1114082704,1016596422)+W(7,-1102176852,1038046228,-1098681477,1044096992);sum2=W(0,-1126607908,-1109006144,-1093467963,1059727060)+W(1,-1111819446,1050929158,1063076656,1073053378)+W(2,1032709615,1025316173,1048889614,1073749745)+W(3,-1119610542,-1107176811,-1090320472,1058093447)+W(4,1027594385,-1123863107,1046933317,-1079533534)+W(5,1029384695,-1122531221,1051206364,-1073154062)+W(6,-1115269200,1026796828,997945380,-1075936158)+W(7,1032209203,-1115616555,-1109796884,-1088004581);WS(-1087442510,1045166814);
sum1=W(0,-1106921670,1032009478,1041337656,-1110338367)+W(1,1032907600,-1127325529,-1100890040,1042108264)+W(2,-1111070674,-1106321881,1060092296,-1105899594)+W(3,1047421629,-1085655355,1044767811,1027442111)+W(4,-1094092352,1057239638,1040377247,-1105935775)+W(5,1031075349,-1098381173,1037296628,1037469097)+W(6,-1136240762,-1128650952,-1131454723,1027139781)+W(7,-1129052086,-1107389381,1037463686,991481919);sum2=W(0,-1119426781,1040351141,-1104019881,1015410156)+W(1,-1109786529,1043540747,-1106797782,1043466418)+W(2,1041819143,-1105926532,-1098594115,1048709183)+W(3,1018220925,-1133247980,1066013053,-1092013542)+W(4,-1103055916,-1096724541,-1136157126,-1109288787)+W(5,-1124599508,1038612076,-1097021086,1027934232)+W(6,986571056,1019567362,1025702119,-1140871148)+W(7,1024618671,-1143357456,1008181894,1027080058);WS(1059279054,1041683061);
sum1=W(0,1028823114,-1096417644,1041071884,1040139175)+W(1,1033060856,-1095251776,1051348966,-1133443258)+W(2,-1136683218,-1096755466,-1106154521,1027763154)+W(3,1041097809,-1095420880,1062896338,1037083176)+W(4,-1108712682,-1087904547,1057053635,-1109247178)+W(5,-1099515041,-1117180600,1050313119,-1169250436)+W(6,-1114499693,-1113115866,1041134484,1007514196)+W(7,-1105525449,-1121084634,1043053335,1031868218);sum2=W(0,-1104031080,1039900182,1028023758,-1125301559)+W(1,-1113246189,1044206765,-1122555834,1027754708)+W(2,-1124792744,1043086617,1041018096,-1129842792)+W(3,-1107688308,1057123143,-1100462314,1022410763)+W(4,-1084040655,1066602722,-1123151815,1034604384)+W(5,-1089958554,1037219700,1032289221,1029558442)+W(6,-1098618924,-1111210157,1028867168,-1139711519)+W(7,-1098033920,1036938090,-1143651414,-1122704124);WS(-1093886876,-1092780259);
sum1=W(0,1031521076,1034696971,-1098366291,991412379)+W(1,1040859655,1027092583,-1107551117,1023411481)+W(2,-1123954783,1057011018,-1084481759,1037665034)+W(3,-1115369432,1055452141,-1086775792,1037775165)+W(4,1027325374,1055461116,1050583573,-1102735091)+W(5,-1130075936,1043845385,-1098824964,-1106471523)+W(6,1017430099,1041326696,1032795870,-1113156096)+W(7,1005655277,1045628689,-1110858724,-1108701199);sum2=W(0,-1099549152,-1115620025,1042476476,-1128057356)+W(1,-1101982776,-1110046443,-1138118945,-1104607948)+W(2,1039636960,1067650764,1056117723,-1129519972)+W(3,1065032135,-1096892917,-1084935200,1039009532)+W(4,1046191187,-1084058149,1043334912,1042222420)+W(5,-1112740199,-1089814493,-1116550886,-1114781123)+W(6,-1120755726,1022618460,1030169574,1023299940)+W(7,-1138571865,-1106519005,-1123579094,1029490149);WS(-1103384376,1050555318);
sum1=W(0,990997212,1056616014,-1113359817,-1104278389)+W(1,-1104723373,1049493908,-1101985253,-1112669305)+W(2,-1102560870,1060440249,-1095607555,-1117918862)+W(3,-1110645588,1063537686,-1091747296,-1124628967)+W(4,-1114771100,1049398171,-1098384586,-1120789735)+W(5,1006886950,-1123261404,-1094355067,1020875660)+W(6,1011892746,1042753094,-1098733239,1029891897)+W(7,1041403778,1041297647,-1099641616,-1143354303);sum2=W(0,-1097904627,1056762738,1033294591,-1113205081)+W(1,-1102268820,998260703,-1102966386,-1105114179)+W(2,-1101696600,1049156882,1040206209,1028552759)+W(3,-1102083058,1055125136,1048772561,1023069474)+W(4,-1100977750,1040009482,1004029807,-1108173489)+W(5,1022682138,-1099421122,1040485303,1040370279)+W(6,-1105396681,-1114104451,-1118051402,-1109779069)+W(7,1035758392,-1112582051,1040482786,-1135668672);WS(1042369848,-1095650924);
sum1=W(0,1032801852,1060985291,-1088222536,-1154392525)+W(1,-1124780413,1056066249,-1093287088,1017158008)+W(2,-1142443027,1059062488,-1089766974,1041310978)+W(3,1031124370,1046815795,-1084610255,-1111535759)+W(4,1024489633,1051554984,-1096293908,-1118760812)+W(5,1037041722,1026983110,1035048291,-1118618480)+W(6,-1157391942,1037131073,-1113190096,1032589425)+W(7,1048283534,1028118439,-1107690581,-1101944856);sum2=W(0,1056251107,-1084477192,-1077785336,1053829707)+W(1,-1118435725,1041984407,-1086371528,-1113013425)+W(2,-1111043713,-1093515412,-1093010832,1046411943)+W(3,-1090037466,1073185178,1074151927,-1090694669)+W(4,-1129656805,1051712939,1054463958,-1095714333)+W(5,-1093926860,1053076395,-1094829660,-1103046632)+W(6,1052716525,-1096065312,-1090812268,1035367276)+W(7,-1083761792,1066458198,1063500158,-1087950464);WS(-1081634407,-1072784825);
sum1=W(0,-1102740818,1024862651,1056867014,1016622683)+W(1,-1115394775,1046040367,1027952685,-1112643478)+W(2,-1101924733,-1109613465,1058509811,-1096240139)+W(3,-1100839185,-1115978107,1050187219,-1101581667)+W(4,-1123768914,1049722038,-1098437541,1008822020)+W(5,-1140848016,-1098661743,1033615035,1023463264)+W(6,-1118249725,-1138059466,-1143195264,-1116668435)+W(7,-1116477425,1025943000,-1132571500,1036595961);sum2=W(0,-1139809909,1046126277,-1119940899,1040903120)+W(1,-1126178115,-1111752353,1055245806,-1104413152)+W(2,1032546581,1034216546,-1088954301,1019748625)+W(3,-1097752958,1042101074,1058677046,-1089277711)+W(4,1042272246,1043290796,-1087007443,1028591970)+W(5,-1118367610,-1112722386,1048637958,-1139620757)+W(6,-1138081685,1034532478,-1140548675,1017306737)+W(7,1017774855,1030093406,1029648824,1033828758);WS(1050645916,1033550915);
sum1=W(0,-1118556120,-1107219907,1039060494,1030703933)+W(1,-1108262319,1043545243,-1145250020,-1110184190)+W(2,1043230361,-1086762442,1059123936,-1110311564)+W(3,-1094947334,-1104041435,1057758321,-1100512367)+W(4,-1103841584,1058293794,-1096913490,1044416908)+W(5,1018079143,-1097977901,1039599795,-1132472896)+W(6,1032598742,1041130248,-1151122424,-1147952664)+W(7,1008731683,-1123331655,-1123961290,1022228292);sum2=W(0,1040267615,-1112791644,1010515766,1024308395)+W(1,1048409433,-1110540665,1032365064,1041630361)+W(2,-1107165984,-1088877638,-1090038325,1040244783)+W(3,-1086251247,1053330884,1049266570,1037513285)+W(4,-1113957324,1057377190,1028890653,-1098504745)+W(5,-1107976602,1057673067,-1103454662,1039941233)+W(6,-1122078587,1024512949,1041725883,-1103661415)+W(7,-1111525785,1042772014,-1143554104,1024552651);WS(1051978908,-1102077462);
sum1=W(0,-1132165009,1045761591,1013540534,-1106078467)+W(1,-1117187439,1051430047,-1096198150,1014010165)+W(2,-1108837850,1060286099,-1130717861,-1121999817)+W(3,1037183202,1046972447,-1085387922,1030141582)+W(4,1028473682,-1128782822,-1105434962,1008925446)+W(5,1045655273,1028047735,-1101497054,1018887490)+W(6,1025240990,-1178179968,-1110960744,-1122721428)+W(7,1033734537,1035331372,-1102517015,1026996307);sum2=W(0,1023072493,974611657,-1101792417,-1112121991)+W(1,-1125531833,1047662948,1051899312,1037288067)+W(2,1030396885,1035351326,1080526024,1042102238)+W(3,-1118880502,-1090109833,-1069022098,-1113214479)+W(4,1027419877,-1110942359,-1087739606,1032127295)+W(5,-1161271853,1033315833,1036440530,-1143368203)+W(6,1019485964,1010290822,-1124554651,-1132377096)+W(7,1028708277,-1156901930,-1114394737,-1141169667);WS(1058455886,-1096183470);
sum1=W(0,-1105360672,-1112611850,1060616064,-1104075433)+W(1,-1112035684,1032735242,1033545283,-1111940643)+W(2,-1105059667,1048808633,1051085625,-1115570744)+W(3,-1103063975,1042817013,-1097442806,-1097216429)+W(4,-1112638549,1058906409,-1102188695,-1107200030)+W(5,-1104182327,1047248804,-1103229812,-1108265532)+W(6,-1106250503,1047193699,-1106970890,-1119499692)+W(7,-1103319623,1057710235,-1109193562,-1106901731);sum2=W(0,-1135393651,-1114274101,-1117767149,-1110403581)+W(1,-1131009665,1016197705,-1130986601,-1136444051)+W(2,1004138181,-1143366053,1026922589,-1112183743)+W(3,-1111055824,1051632163,1048764370,-1121253595)+W(4,-1134829555,-1111579981,1036257166,1009689523)+W(5,-1127256265,1038147066,-1112945554,989872074)+W(6,-1113946573,1025185617,-1143942149,-1123668797)+W(7,1010148467,-1137859715,-1123068365,-1123716033);WS(-1103618872,1023577831);
sum1=W(0,1041702149,1057806109,-1091063799,1022049043)+W(1,1032268701,997904496,-1106010126,-1102660926)+W(2,1021026046,1057675340,-1090884608,1046995709)+W(3,1032012647,-1129702414,-1094077941,-1100395542)+W(4,1023662430,1056283152,-1094732237,1050214494)+W(5,-1111766616,1039716321,-1100869456,-1096243374)+W(6,-1112590149,1049875952,-1105996279,1047647816)+W(7,1042231991,1054291708,-1098425069,-1100607928);sum2=W(0,1073849383,-1072987051,1040644897,1022236877)+W(1,1069429154,-1080077361,-1098556311,-1128073567)+W(2,1070121938,-1076996297,-1124122091,-1118780260)+W(3,1066905653,-1086754234,-1095882058,1027638421)+W(4,-1087755842,1060194671,-1096747545,1012182550)+W(5,-1080359597,1067521081,1048551041,-1129108935)+W(6,-1073496568,1074652354,-1092793409,-1130588931)+W(7,-1070245916,1075883836,1058695504,1001812541);WS(1010873216,-1100304815);
sum1=W(0,-1154187044,1045945805,-1102222630,-1113759340)+W(1,1028741017,1051026373,-1103217414,1022415534)+W(2,-1114247598,1058185854,-1097780567,-1105383733)+W(3,-1099084427,1059904750,-1091550752,-1111624796)+W(4,-1104966895,1052860588,-1108718914,-1114326870)+W(5,994968800,1038231664,-1110664976,-1110217221)+W(6,-1113228468,1040557287,1017403508,-1108875519)+W(7,1028263947,1032103905,1017865354,-1109350878);sum2=W(0,-1114639192,-1100331344,1035901690,1012858414)+W(1,1039210963,1069298433,1043940791,-1126620651)+W(2,1047528380,1080352854,1030733380,1036529177)+W(3,-1099502544,-1067747068,-1084572959,-1099630936)+W(4,1041344628,-1080996124,1003800555,1043527822)+W(5,-1108972702,1032407437,1045939813,-1119860547)+W(6,1021595805,-1121090437,-1121287047,-1145664907)+W(7,-1116883371,1016604711,-1122259179,1034105585);WS(1044302648,-1104457270);
sum1=W(0,-1115179413,1029190781,-1108944696,-1115207128)+W(1,-1101763748,1045938783,-1102720380,1013266237)+W(2,999269803,1034810490,1038235218,1025157307)+W(3,-1106420033,1055724168,-1101615303,-1105407492)+W(4,1041707045,1053359959,-1094303566,1045691477)+W(5,-1128885581,-1100033022,1043259278,-1113033137)+W(6,-1110751840,1037908026,1011056201,-1114066571)+W(7,1029110244,1035419021,-1123807773,-1113282394);sum2=W(0,-1117238549,-1109414288,-1115125848,1023475415)+W(1,-1115295266,-1128441429,-1121954754,1024122972)+W(2,1033754662,-1104877135,1018153798,1002646200)+W(3,-1095438097,1053172955,1038786210,-1106263750)+W(4,-1106855439,1056926069,-1104082080,1034246226)+W(5,1011060498,-1108715476,1043675119,1025499367)+W(6,-1117460606,1036225840,1008366234,-1107090094)+W(7,1032653312,-1114450934,1018894269,1013321052);WS(1068015911,1043072951);
sum1=W(0,-1127841379,-1101991257,1041159238,1035382295)+W(1,1035792844,-1091973141,1040826438,-1098419575)+W(2,-1155603908,-1110119406,1052691071,1043898844)+W(3,1018341976,-1095315357,1053842800,1030324599)+W(4,-1111053022,-1107228151,1042506601,-1108241413)+W(5,1044403491,-1111437840,1050221764,1043481954)+W(6,-1112313859,-1097295811,1030249017,-1098652336)+W(7,1005208661,-1103670736,1046985745,1032196534);sum2=W(0,-1134315530,-1125722365,-1135384490,-1118933131)+W(1,1033824390,1019923991,998580556,1027495017)+W(2,-1112867968,1039464885,-1093291922,1045077367)+W(3,1039862799,-1087456726,-1061395777,1087627027)+W(4,1005143468,-1119378177,-1106942114,1034637079)+W(5,-1114969920,1042059959,-1121281813,-1148550692)+W(6,1030354102,-1113780490,1034179020,-1118611519)+W(7,-1131720457,1009971850,1032010553,-1117397469);WS(1060186318,-1131602669);
sum1=W(0,1022422466,1050205114,-1099402401,-1112848707)+W(1,-1102049002,1052887138,-1102238785,-1106285089)+W(2,1050775273,1052456073,-1100510367,1039607513)+W(3,-1097141731,1049038746,-1088759247,-1098786589)+W(4,1056872997,1040490435,-1122526498,1048305743)+W(5,-1099566807,1039690728,-1099089908,-1104192622)+W(6,1025667942,1043457059,-1102859210,1032266998)+W(7,1032894309,1045856748,-1106963501,-1118572779);sum2=W(0,989650422,-1120410947,1047633630,-1081060940)+W(1,-1108234271,1050158699,1066272871,-1074101109)+W(2,-1120122674,-1092804082,1075424781,-1079387458)+W(3,1045260201,1024838498,1061734347,1050344942)+W(4,-1114112879,-1125280065,-1091697647,1043540897)+W(5,1037831837,-1119936776,1003481288,1039609275)+W(6,-1117501250,-1114421818,1011848513,-1131708367)+W(7,1024132690,1035095434,-1106020023,1026462111);WS(1057810382,986287880);
sum1=W(0,-1105255365,-1110142276,1041191503,1050176972)+W(1,1027767677,-1106138450,1031406779,-1130243957)+W(2,1037147968,-1092238936,1027980992,1041310918)+W(3,1038550632,-1090210593,1049547413,1041377527)+W(4,-1136315263,-1089134184,1052451129,-1115128119)+W(5,1035749561,-1093055129,1057536820,1033537239)+W(6,-1115075413,-1097497096,1050343212,-1127231554)+W(7,1028257967,-1089420006,1058108487,1031965752);sum2=W(0,-1099824579,1070708271,1075074245,-1097074436)+W(1,-1113793286,-1104040400,-1084124078,1023561426)+W(2,1053512844,-1091831853,-1082668198,1039380165)+W(3,-1112943238,-1072548459,-1072503695,1009216489)+W(4,1041834894,-1093778092,1056090411,1043969626)+W(5,-1099992002,1057576575,1053907302,-1107563771)+W(6,-1120789532,1064181862,1058602971,1034348623)+W(7,1024916046,1051972140,1054786345,-1106961801);WS(-1075707047,1038147646);
sum1=W(0,1038492938,1050722763,-1095596015,1040870942)+W(1,-1115961531,1026800423,-1103730686,-1122935577)+W(2,1036899040,1055626176,-1091210886,1047700685)+W(3,1041066756,1052178217,-1090286882,1036539085)+W(4,1038870159,1027667391,-1094135001,-1102625947)+W(5,1045702796,1053246416,-1095582752,1048523811)+W(6,1022987667,-1100305296,-1109653838,-1105859960)+W(7,1044017707,1049962981,-1093296229,-1117734303);sum2=W(0,-1145353723,1027969677,-1115030411,1052090154)+W(1,-1113260796,-1095928859,1031463199,-1110261785)+W(2,-1112198364,1052169305,-1108227013,1041877601)+W(3,-1113367096,1052353113,1051016428,-1099630700)+W(4,1007958125,-1129450520,1041462653,-1087173862)+W(5,1047146251,1051473061,1045242344,-1102681887)+W(6,-1122974002,-1091037095,1032341221,-1095485390)+W(7,1021064313,1050393555,1020102815,-1111896409);WS(-1102302520,1068562064);
sum1=W(0,-1130894152,-1101486038,1044130034,1031789673)+W(1,1029216267,-1094978851,1029251017,-1102217970)+W(2,1029150351,-1104755260,1053252560,1042516209)+W(3,1029804895,-1093484995,1050941559,1040658618)+W(4,-1108054071,-1110271975,1036880709,-1113036417)+W(5,1046304488,-1106599349,1050863202,1041743615)+W(6,-1107326720,-1102131284,-1128083416,-1102226940)+W(7,1018120580,-1102274525,1047248574,1032422999);sum2=W(0,1019111797,1022527979,-1131519898,1029130971)+W(1,-1123809812,-1111065998,1023737355,-1117143513)+W(2,1006739898,1031759809,1045357020,-1106220344)+W(3,1041109085,-1095097056,1082939698,-1064938697)+W(4,-1126211453,1034613952,1027342607,-1122955245)+W(5,1028972357,-1107360163,1033832936,-1112280546)+W(6,-1118372569,1033659253,-1112248823,1032152906)+W(7,1025713585,-1118642675,-1118824157,1028082979);WS(1066566439,-1125753148);
sum1=W(0,1020091828,-1096367972,1038767583,1030663671)+W(1,1041951168,-1098758994,1048997640,1025331919)+W(2,-1130301450,-1093467737,-1130818632,-1108818909)+W(3,1052053147,-1089881409,1064063659,1044746920)+W(4,-1131231944,-1092544881,-1116991019,1022962726)+W(5,1033588155,-1098181717,1042770882,1041997189)+W(6,1009411772,-1110070786,1046860728,1018371147)+W(7,-1116682291,-1096392077,1027361773,1038578846);sum2=W(0,-1105507764,1019815533,-1136431769,1024962860)+W(1,-1149004498,1047279899,-1121679526,1041000955)+W(2,-1098298748,-1106660204,-1096656341,-1107413740)+W(3,-1115729482,1058550934,1058580319,1027135608)+W(4,-1094576030,1031191852,-1098228632,-1101441076)+W(5,-1111478010,1032716298,1041490224,1035067556)+W(6,-1129010369,-1117054989,1047791827,-1123460834)+W(7,1018600957,1019851909,-1106522387,1005788722);WS(1050996380,1066787661);
sum1=W(0,1042843177,-1109518091,-1098674409,-1112832565)+W(1,-1120310187,1043911830,-1097687209,-1133582755)+W(2,1033453959,1059519229,-1096304487,-1116528532)+W(3,-1107450543,1061971625,-1098011863,-1105396874)+W(4,1017862620,1051823058,-1095767039,1033796902)+W(5,-1134072575,1046601317,-1095249970,999923683)+W(6,1025308393,1042112788,-1098354285,1030029487)+W(7,1033769739,1046863997,-1098417599,-1109771063);sum2=W(0,-1103321099,-1087654445,-1098379129,1013739975)+W(1,1033376724,-1114493691,-1096458683,1015354012)+W(2,-1108916223,1049058628,1036368268,-1121134774)+W(3,1033194077,1065240604,1054396447,-1115257551)+W(4,1038197771,-1128335788,1049730119,-1129699908)+W(5,1032881798,-1094150295,-1108472207,1021079748)+W(6,1017830932,1006224046,1031462702,-1117224382)+W(7,-1138730935,-1112103411,-1102017203,1038189385);WS(1027314912,-1081149641);
sum1=W(0,-1109480125,1051429188,-1118844062,-1097611416)+W(1,-1114947760,1053252314,-1094077252,1034118735)+W(2,-1101195017,1058130398,-1113091794,-1104617542)+W(3,-1132100201,1061393767,-1085308129,1035982720)+W(4,-1103759537,1057940398,-1102037735,-1114189097)+W(5,1044342469,-1104522586,-1094497965,1036294793)+W(6,-1111893319,1055491172,-1103334896,-1128796810)+W(7,1051194426,-1120202825,-1094870250,1030785028);sum2=W(0,-1131039707,-1098833779,-1147567565,1035790053)+W(1,1024995350,-1124760267,1057070390,995065627)+W(2,-1104486127,-1078713050,-1091843304,1037354874)+W(3,1015537291,-1065942779,-1081156610,-1154356731)+W(4,1053996441,1047686732,-1094140189,-1107145709)+W(5,-1103676904,1084085461,1060423478,1026796886)+W(6,1047124046,1064521940,1046849692,-1108476011)+W(7,-1111129691,-1093915430,1018309905,1038591472);WS(-1081542375,1044780323);
sum1=W(0,1026864081,1046719985,-1098857847,-1114219435)+W(1,-1100303790,1054288460,-1108679899,-1104586877)+W(2,1048337215,1054459103,-1098101851,1041408644)+W(3,-1098110473,1048901488,-1093175556,-1098306531)+W(4,1054474587,1041639871,-1104037973,1046672715)+W(5,-1099969099,1034589376,-1107626335,-1104199322)+W(6,1023999910,1043694031,-1101510966,1022681657)+W(7,1028627178,1046235480,-1106600025,-1126646775);sum2=W(0,1017985090,1024212320,-1099849981,1067245211)+W(1,1027847194,-1098721130,-1081468176,1074345814)+W(2,1036519222,1050387030,-1070464929,1070597407)+W(3,-1113167123,-1094712479,-1096550174,-1088417301)+W(4,1037009826,-1100822056,1057690620,-1104880956)+W(5,-1113380621,1028269032,1042714784,-1102737214)+W(6,1031131596,1009055356,-1145638655,1000105719)+W(7,-1115360802,-1113841920,1046010973,-1112342255);WS(1059294542,1020616832);
sum1=W(0,-1157534552,-1096856701,1050532499,-1112831597)+W(1,1039080142,1044861738,1041652423,1046540791)+W(2,-1097783100,-1089052876,1057029426,-1098369827)+W(3,1031217968,-1085780263,1047119538,1040272239)+W(4,-1164216296,1044573672,1039715347,1024931118)+W(5,-1138897989,-1097342660,1043073721,-1103025619)+W(6,1026686634,1041475528,1040308239,1045404192)+W(7,-1105498094,-1105558033,1048391538,-1114523696);sum2=W(0,-1106291706,1040318024,-1114208076,-1142193319)+W(1,1001372950,-1105705183,-1116263519,-1145917455)+W(2,-1099590495,1045484852,-1108179199,1036599633)+W(3,-1093748925,1061316313,1049891427,-1108356360)+W(4,1015225205,-1098311584,1040668388,-1148092276)+W(5,-1105937891,1041085521,-1111581107,1032743264)+W(6,-1112612361,1028378294,-1115787941,1021281994)+W(7,995169980,1035732349,-1113959318,1024794158);WS(1059376718,-1137270291);
sum1=W(0,-1118257199,1043258576,-1114290826,-1112002778)+W(1,1037392427,-1106073464,-1124279079,1022160871)+W(2,-1097794403,1054680411,-1115190716,1045843716)+W(3,1035766677,-1099046488,1052189312,1011458515)+W(4,1026067385,-1088020070,1054691490,-1110958220)+W(5,1032186693,1041392887,-1097245116,1046761570)+W(6,-1108679762,-1113652045,1025610423,-1117145658)+W(7,-1139304576,-1111666975,-1123561026,1032305501);sum2=W(0,1025244035,1033595807,1016573022,1002397687)+W(1,-1122852568,-1087687504,1048825911,-1104089806)+W(2,-1092220395,1066421651,1058107887,-1130145014)+W(3,1038019467,1047700223,-1089540205,-1111655831)+W(4,1048072683,-1084925862,1045215493,1032935415)+W(5,-1113553750,1050883425,-1098430697,1015641098)+W(6,-1119930901,-1105555859,1041208433,1001885951)+W(7,-1139793711,-1146566911,-1124843514,-1131703250);WS(1058596686,1013962118);
sum1=W(0,1000024554,1052551424,-1088298614,1039656505)+W(1,-1127551432,1049056438,-1098656348,1034731345)+W(2,-1100000762,1057499982,-1090756927,1019232187)+W(3,1035333436,1036076760,-1097067922,1033429441)+W(4,-1122612871,-1127972943,1040213184,-1125045580)+W(5,1044766998,-1116046252,1015197910,-1113717771)+W(6,1041477861,-1118015335,-1123679237,1037833508)+W(7,1051562743,-1099275107,-1122278672,-1122272135);sum2=W(0,-1104434141,1048601996,1033271157,1004930429)+W(1,1029025211,-1091369704,-1119340081,1028438774)+W(2,-1078497608,1052827694,1025214064,-1106316897)+W(3,-1079110377,-1106615386,-1109539756,1034989376)+W(4,-1085502108,-1115334546,1050957039,-1108631008)+W(5,1066279808,1037382016,-1106594885,1023198169)+W(6,1062913146,-1122817088,1036274829,-1134348613)+W(7,1068620036,1048688798,-1118139306,-1139733884);WS(1044771128,1023341948);
sum1=W(0,-1156220044,-1092336191,1051560294,1036528391)+W(1,1034545464,-1098819215,1044146859,1029114797)+W(2,1033488922,-1096491302,1051910286,1022761170)+W(3,-1111313058,-1086850728,1045449190,1029767950)+W(4,1038420969,-1102939421,1053458817,1041877300)+W(5,1008511890,-1100928894,1038883707,1034675856)+W(6,1013986230,-1115524377,1012126018,1037411178)+W(7,1011084871,-1089482302,1046748951,1043196317);sum2=W(0,-1071004894,1076503146,1057610169,-1122913984)+W(1,-1080574884,1066884159,-1107351326,-1130255370)+W(2,-1089987082,1058011283,1054000347,1038970611)+W(3,1049506323,-1098882467,-1090234844,1014162118)+W(4,1065282653,-1084978169,1030898490,-1114000490)+W(5,1062249589,-1088626314,-1090230279,1022492087)+W(6,1060165079,-1082249713,1044380003,-1131621088)+W(7,1070844945,-1077734377,-1096516163,1013009282);WS(-1111817840,-1134998409);
sum1=W(0,1022731056,-1102901203,1029699069,1021112442)+W(1,1045262352,-1094315057,1052915216,-1107194439)+W(2,1044888721,-1085070720,1058770140,-1097785743)+W(3,1029818259,-1111793509,1057078063,-1117717150)+W(4,-1105915720,1055206544,-1095183540,1040740592)+W(5,-1114660906,1046806370,-1097451385,1036425016)+W(6,1027479949,-1123039746,-1112670352,1005586201)+W(7,991785104,-1136267423,-1114500629,1016465988);sum2=W(0,-1129690332,-1113356803,997943457,1015499837)+W(1,1030842707,1026318374,-1119512995,-1180561029)+W(2,-1123486113,1041923626,1037525758,-1144014736)+W(3,1054087898,-1089332833,-1088292904,1037328869)+W(4,-1105176966,1068558125,1040210770,-1107365912)+W(5,-1097205966,-1141184456,1050151959,-1114055561)+W(6,-1098021434,-1107728348,1018682892,1009592392)+W(7,-1106929221,-1104288342,1006954668,1013301204);WS(-1100650808,1043653943);
sum1=W(0,1038392637,1044290651,-1095199164,1033771919)+W(1,1032036848,1040683515,-1115398639,1038316223)+W(2,-1120772452,-1106266873,-1094097345,1042896310)+W(3,1043637149,-1090111931,-1097393337,1045751664)+W(4,1040259489,-1133467790,-1104941765,-1159203906)+W(5,1047398869,1044787930,-1101572298,1015063331)+W(6,1038054351,1023591523,1016760834,1030908740)+W(7,1050576478,1037223428,-1102689443,-1125005703);sum2=W(0,1018053796,1046306039,-1101305605,1031448374)+W(1,1000548496,1043541862,1029064982,-1112893849)+W(2,1049079603,1010667960,-1116813778,1021972628)+W(3,1039189619,1064529690,1038487223,-1105518867)+W(4,-1128574308,1047996002,-1100258391,1037842238)+W(5,-1118597354,-1087406141,1048794746,1033382833)+W(6,-1106984497,-1095617964,-1114392997,1021089548)+W(7,-1104543855,-1086946593,1045938007,-1140458600);WS(-1121537248,1047151836);
sum1=W(0,-1096325448,1052654400,1000450324,-1116556387)+W(1,-1113135282,1035132488,-1110395025,1023519458)+W(2,-1098188693,1046868890,-1139200797,-1111260975)+W(3,-1112146268,-1134150082,1049727010,-1110207458)+W(4,-1108791588,-1129891280,1041189572,-1104838938)+W(5,-1117696601,-1098847494,1056884317,-1098805187)+W(6,-1123869651,1032919412,1041128337,-1146298440)+W(7,-1114157115,-1107856679,1058220805,-1103148146);sum2=W(0,-1142864271,1043572739,-1125571574,-1107989855)+W(1,1021304865,1026011378,1028667063,-1140649559)+W(2,1043366966,-1102859954,1022196210,1020722946)+W(3,-1107584343,-1080136051,-1072538638,-1132367054)+W(4,1014758407,-1103597159,-1076945816,1041979768)+W(5,-1130465374,-1115654645,1048815254,-1126224006)+W(6,-1120740451,1046511165,1072551214,1027667511)+W(7,1000478551,1053224660,1074776028,1048839210);WS(-1086568910,969651201);
sum1=W(0,-1128189323,-1096064919,1047521403,1043461231)+W(1,1044154939,-1089612648,1054908701,-1099266659)+W(2,1043534732,-1084798775,1056987371,-1113308531)+W(3,-1114366976,1053159863,1057685165,-1152040120)+W(4,-1098469330,1053431542,-1089249613,1042761408)+W(5,-1101372520,1050787607,-1090701774,1049635020)+W(6,-1123038043,1036747448,-1105030179,1010635844)+W(7,-1132910587,-1116020373,1027268120,1018344000);sum2=W(0,1042932965,-1103892922,-1104364155,-1139842168)+W(1,-1103428495,1060495074,1060109323,-1118896922)+W(2,1039997403,1052448567,1064108701,991756114)+W(3,-1093583228,-1075640666,-1073056297,-1097481656)+W(4,1044856824,1057723154,1055665788,1040659602)+W(5,-1121819542,1057002090,1060503917,-1099984054)+W(6,-1177180368,-1112150955,-1116550688,1034919451)+W(7,1028413178,-1118134166,-1110515035,1041069777);WS(-1084093518,-1116656412);
sum1=W(0,1002008836,1058416208,-1096672513,-1112390467)+W(1,959481663,1026388179,-1109778819,1023428581)+W(2,-1104590931,1059097973,-1088144465,-1112632704)+W(3,1050696243,1042079029,-1096264126,1040470858)+W(4,-1106608235,1041679827,-1101432288,-1102954054)+W(5,1047962207,1049127990,-1100480244,1047012782)+W(6,1030562773,1031439243,-1113594772,-1112144502)+W(7,1015783795,1042535660,-1093923750,-1145396437);sum2=W(0,1007960967,1027407916,-1129957403,-1132155403)+W(1,-1110192070,1010716935,1018303319,-1121935910)+W(2,1049899326,-1097456083,1037417999,-1137993343)+W(3,1056650247,-1070859565,-1094713389,-1142796285)+W(4,1078512141,-1068241064,-1096379657,1039214170)+W(5,1081472440,-1079514242,1043613542,-1111213656)+W(6,1058404171,-1094427160,1025537830,1032528613)+W(7,999915485,1030657127,-1116925932,1024356221);WS(1052225948,1018668194);
sum1=W(0,-1120453498,1051775516,-1117579103,-1107074656)+W(1,-1123160289,1048325451,-1111291056,-1112742544)+W(2,-1108654867,1058214550,-1093397513,-1147977428)+W(3,-1104839613,1064670427,-1091445969,-1119335936)+W(4,1041378113,-1126638409,-1092047898,-1109154218)+W(5,1036965515,1049967085,-1099225050,1034167881)+W(6,1044186084,-1096299613,-1112850625,-1138567959)+W(7,1034438594,-1128237844,-1112057991,1019177609);sum2=W(0,-1121001958,-1117606942,-1103097305,-1130038396)+W(1,-1148685985,-1111847761,1021935234,-1112487949)+W(2,1018483434,-1120566718,1049895592,1038078839)+W(3,1021815720,-1076982600,-1081972918,-1125812992)+W(4,1049361594,1074852012,1051964198,-1152546434)+W(5,-1108634723,1048076514,1040925857,-1104919092)+W(6,-1132118692,-1102180777,1017568960,1026180028)+W(7,-1105580672,-1116866514,1040155911,-1123068468);WS(-1096382876,-1091051652);
sum1=W(0,-1116126267,1057278592,-1096000788,-1116910752)+W(1,-1113197617,1048826126,-1097274020,-1140807037)+W(2,-1112424211,1058810754,-1088739494,1039925053)+W(3,-1124324715,1056304110,-1091311905,-1132679170)+W(4,-1136579346,1041995897,-1114916522,-1107191661)+W(5,1040875430,1016295122,1038826452,-1119450067)+W(6,-1113905512,1024916389,-1128507781,1023437062)+W(7,1017323784,1042534003,1017648027,-1098370349);sum2=W(0,-1120311657,1025682064,1036682152,-1108273289)+W(1,1036113080,-1107470193,-1108061877,1012612647)+W(2,-1109045199,1035621932,1051542033,-1101063214)+W(3,1029662296,-1118009189,-1101792442,-1076098595)+W(4,-1122358251,1045290388,-1093646778,-1080861029)+W(5,-1114085873,1009830751,1056395710,1039398973)+W(6,1016737279,1035169596,-1091719234,1065137390)+W(7,-1115835645,1030264440,1052430993,1072502688);WS(1040082544,-1114755812);
sum1=W(0,1017784372,-1110974758,1040296296,1024480479)+W(1,1037505264,-1108514902,1041424680,-1104471944)+W(2,1045745417,-1095324708,1054913780,-1106439461)+W(3,1019379817,1052579502,-1106396419,-1115066496)+W(4,-1109308706,1058051822,-1087512533,1040857799)+W(5,-1124056118,1046163210,-1093666877,1001482384)+W(6,1025470519,1038459986,-1106674096,995688529)+W(7,1039469090,998280780,-1109356390,-1108404770);sum2=W(0,-1162396366,1045315846,1034748092,1035646876)+W(1,-1117720653,-1118054954,1034773210,-1100298043)+W(2,-1104226850,1057942904,1043388435,-1097646834)+W(3,-1105580348,1059476362,1067689202,-1093789486)+W(4,-1105643813,-1090022037,-1083232471,1040357620)+W(5,1031813906,1045409162,-1101262587,-1113573448)+W(6,1011045214,-1106412098,-1124577575,1012935222)+W(7,1018164327,1023977529,-1102021751,1024454049);WS(1036525168,-1082462584);
sum1=W(0,-1116308971,-1085123800,1057675329,1019612704)+W(1,1037298441,-1087372070,1051660338,1027541711)+W(2,1027885589,-1086414101,1059597873,-1109257541)+W(3,-1122874917,-1096064460,1059581688,1041073820)+W(4,-1154089797,-1099879381,1052784510,1028059367)+W(5,-1108384819,-1104319094,-1117339864,1045372305)+W(6,1028179743,-1127380522,1039251609,1031554934)+W(7,1003463273,-1096394215,-1110971807,1053758651);sum2=W(0,1060691160,-1081285622,-1080809247,1052276353)+W(1,-1103295177,-1090050073,1050684042,-1106187369)+W(2,1035985281,-1102851017,-1087522637,1048638013)+W(3,-1085964582,1072728426,1060852217,-1090587145)+W(4,-1105398566,1060511611,1058511518,1029176048)+W(5,-1107551093,1033954581,1041242888,-1094879840)+W(6,1049030608,-1086630634,1028348456,1046256182)+W(7,-1090293163,1058069039,1062481845,-1087039462);WS(-1074352935,1040600857);
sum1=W(0,1042034194,1057627204,-1090157751,1024364622)+W(1,1028652336,1025049468,-1105875707,-1105990299)+W(2,1024054004,1057567995,-1088931067,1048022018)+W(3,1030695172,1022098295,-1095088235,-1100928004)+W(4,1029627411,1052602222,-1094832321,1049957878)+W(5,-1117605317,1039437212,-1104356174,-1095846092)+W(6,-1114002447,1049556590,-1107260676,1047165477)+W(7,1041624512,1053416947,-1101255271,-1098759166);sum2=W(0,-1075440350,1073165865,-1112383192,-1148975848)+W(1,-1079714919,1065983198,1048707236,-1115591486)+W(2,-1079134350,1068716226,-1135853868,1038054064)+W(3,-1081735031,1066499710,-1098543278,-1125971282)+W(4,1055569671,-1095308006,1021808504,1040311395)+W(5,1066585571,-1080754250,-1108920844,-1110109816)+W(6,1071644179,-1074800849,1050977418,1035370814)+W(7,1075476470,-1073191304,-1090378667,-1120408347);WS(1041022776,1033480094);
sum1=W(0,-1132576057,1026327841,-1110434490,-1119031508)+W(1,-1123321429,1042302896,-1109312954,1021323174)+W(2,1028959481,1052457903,-1089918670,1029242558)+W(3,-1104176578,1063677500,1025377120,-1118638740)+W(4,1046472198,-1097607903,-1090934974,1013298461)+W(5,-1121060138,-1123802109,1046523967,-1106699146)+W(6,1027556403,-1118671609,-1112257611,1030036314)+W(7,-1115611836,1039698959,1000531209,-1116635705);sum2=W(0,-1106027239,1049930690,-1110218398,1034564779)+W(1,-1122286155,-1127267122,-1108798456,1018367610)+W(2,-1102546078,1041115945,1058786995,-1095860458)+W(3,1055155948,-1091935564,1075372513,1043590800)+W(4,-1096754888,1052250618,-1071163371,-1112711414)+W(5,1032068992,-1103388917,-1123143101,-1119323979)+W(6,-1121774513,1038737216,-1121707895,1016553114)+W(7,1036170969,-1108790214,1032355550,1017858173);WS(1055618972,-1117202987);
sum1=W(0,1030962480,1039894129,-1101932469,1031993659)+W(1,-1101414710,1053882576,-1089999221,1048656807)+W(2,-1098100923,1057347458,-1085784352,1043352452)+W(3,-1111740150,1049814740,1051098296,1031031542)+W(4,1036980413,-1090053902,1056052448,-1104607674)+W(5,1041005827,-1088233382,1051763396,-1119077705)+W(6,1021681163,-1105970903,1044301630,1022017143)+W(7,-1112834597,-1117339136,1032801282,1039235901);sum2=W(0,-1114659327,-1101541229,-1107338771,1039378885)+W(1,-1123577690,1043634319,1057974128,-1111523166)+W(2,1042921002,1066882360,1050113378,1040130625)+W(3,-1105097716,-1077668162,-1080704784,-1104122760)+W(4,1042773509,1037629509,1051155360,1012227066)+W(5,-1093975266,1058638399,1052705661,-1110420726)+W(6,1032061179,-1108208741,1008396554,-1125218199)+W(7,1000405669,-1131856909,-1111189711,1025207949);WS(-1091387548,-1116324289);
sum1=W(0,1026642697,-1112220622,1049897926,1027958127)+W(1,1044682252,-1093973688,1047211372,-1098544270)+W(2,1041967213,1046046637,1050365286,-1112662293)+W(3,1032214050,-1086442024,-1112122925,-1106755108)+W(4,-1131062694,-1099996941,1046223135,-1116559746)+W(5,1015214154,1053177927,-1132096750,1034258897)+W(6,-1137069945,-1098783494,1024489425,-1111108842)+W(7,-1110158325,1037567917,1042021623,1031638516);sum2=W(0,-1108095393,1011776651,-1101257730,1019145070)+W(1,1016776222,1024100809,-1105403134,1032882678)+W(2,977935538,-1097248934,-1101986254,-1124027994)+W(3,-1122468710,1057627889,1060632600,-1103033100)+W(4,1019959206,1042194141,-1090719303,1039533068)+W(5,1030099429,-1117226417,1037412790,-1110127978)+W(6,-1104930054,1051928720,-1109292621,-1125661478)+W(7,1002749526,1041814459,-1115385474,-1108291818);WS(1057965518,-1118811194);
sum1=W(0,-1104352985,-1106566686,1052732873,-1107147458)+W(1,1038892389,-1112643723,1003767366,-1114250980)+W(2,-1105058276,1026830542,1060358287,-1096574819)+W(3,1042490232,-1091938531,1019887594,1048844541)+W(4,-1121521774,1058056073,-1118338013,1024329053)+W(5,-1099594944,-1101314965,1042464324,-1107780158)+W(6,1033536020,-1098044778,1024562028,1032778872)+W(7,-1095161930,1039936570,1046000094,-1107207172);sum2=W(0,-1116205334,993944814,1032713731,-1106373772)+W(1,1042905425,-1113078065,-1104977559,1039619019)+W(2,-1109155755,1044406596,1048672381,-1115343154)+W(3,1044205280,1040105843,-1104277422,1048332350)+W(4,1035597621,1043112037,-1103087244,999501191)+W(5,1008636092,-1123380436,-1153474446,-1106439836)+W(6,1036458751,-1105268129,1015784078,1021528398)+W(7,-1092853308,1005260887,1036094123,-1106473413);WS(1053420700,1049909457);
sum1=W(0,-1115258034,-1106165874,1050401361,-1113250117)+W(1,1034071238,-1089903413,1041332866,1023742249)+W(2,1027276239,1036166247,1049384898,-1130552842)+W(3,-1115686559,-1100423414,1037380859,-1120158506)+W(4,1041096236,-1093491554,1052388787,1037333727)+W(5,-1102788144,1049835542,1034784425,-1103514783)+W(6,1034068157,-1095323722,1031952854,1037170040)+W(7,-1107460367,-1110396954,1050882791,-1114330639);sum2=W(0,-1112500393,1024557142,-1136367764,1020782048)+W(1,1028289272,-1165623582,1035333264,-1122738507)+W(2,1049127312,-1095250820,-1114028070,1025362120)+W(3,1086771603,-1062269001,-1087155359,1034731082)+W(4,1048088739,-1095068995,1022077560,-1125007838)+W(5,1020087240,999933935,1034746908,-1120796207)+W(6,1014851096,-1135945992,-1120864651,1026594640)+W(7,-1146529543,1025716258,-1127622484,-1128255426);WS(1063806286,1027083983);
sum1=W(0,-1114823180,1045480194,-1118427516,-1109705966)+W(1,1030313470,1039206373,-1106496703,1020453816)+W(2,-1111791457,1061885616,1010686340,-1103432478)+W(3,-1111977289,1050451993,-1083830979,1039658735)+W(4,-1108043857,1057912708,-1099420545,-1114670584)+W(5,1019729830,1036575619,-1105267089,-1109909656)+W(6,-1114640622,1039765761,-1131920190,-1113587473)+W(7,1033983240,1034424532,-1125840468,-1112770081);sum2=W(0,1033978022,-1122290634,1016780797,-1164938552)+W(1,-1100194899,-1091664523,-1103111994,1002490582)+W(2,1033701105,-1071413373,1047766898,-1105595809)+W(3,1050426550,1075108998,-1096749849,1051489664)+W(4,-1104028404,1062092502,1027350687,-1108336227)+W(5,1034191613,-1103668501,-1131589290,1021076655)+W(6,-1141130302,1034149895,-1131724600,-1149103768)+W(7,1010895851,-1140709165,1027888251,-1131210373);WS(1058288590,1045994186);
sum1=W(0,1018135640,-1093342072,1052167946,1038262801)+W(1,-1123855059,-1096797372,1041780692,1015346466)+W(2,1040223430,-1086390197,1052872019,-1132654257)+W(3,-1112801779,-1105293320,1059840396,-1134794696)+W(4,1036317947,-1091216419,1051866430,-1117665797)+W(5,-1098800665,-1117054299,1050341107,1012611090)+W(6,1034707665,-1096209979,1048652350,-1139713758)+W(7,-1096517871,1023470716,1050625648,1010858330);sum2=W(0,1041114210,-1099008397,-1123917868,-1125418381)+W(1,-1099284356,1047276236,-1111523652,-1120564910)+W(2,1038292116,-1081084758,1037708884,1020505319)+W(3,-1092208278,-1071665325,-1086778305,-1100128811)+W(4,1054381469,1054365119,-1101037019,1024474915)+W(5,-1104534119,1081581342,1026238413,-1125603475)+W(6,1025804573,1062322644,-1134916894,1025011807)+W(7,1033400256,-1093538640,1052085127,-1103707544);WS(-1088887374,1070119449);
sum1=W(0,1040460421,1052058645,-1090595183,-1105506686)+W(1,1041554590,1048371361,-1115426747,1029097335)+W(2,1013850612,1048732808,-1094790815,-1129317061)+W(3,1038262022,1042754705,-1087902678,1001782464)+W(4,1042710919,1047384127,-1106656361,1038072126)+W(5,-1106869091,1054439312,-1090477876,-1131475029)+W(6,1044864290,1032508990,-1122940954,1028935005)+W(7,1046057615,1042772520,-1091795237,-1119515740);sum2=W(0,1024604999,1056461606,1071685965,-1075212110)+W(1,-1112923336,1030035123,1066713447,-1080779344)+W(2,1027433809,1050727550,1068313262,-1078194918)+W(3,1025504127,-1090534096,1028028856,-1153515923)+W(4,1007245204,-1105339223,-1081367671,1068056044)+W(5,-1144581942,-1095507508,-1078816510,1069903211)+W(6,-1129047399,1043793174,-1081156501,1064173276)+W(7,1021294865,-1095638178,-1090770344,1060536751);WS(1040470840,1011790950);
sum1=W(0,1015095158,1043725275,-1105535856,-1108386992)+W(1,-1120734562,1051465082,-1108441440,1030149375)+W(2,-1116691398,1058372660,-1095343471,-1112701741)+W(3,-1118217942,1055309890,-1081260869,1026499745)+W(4,1019898057,1046636817,1047492563,1032201014)+W(5,-1123629847,1044874098,-1093096561,-1115283258)+W(6,1034607368,1043010193,-1105294873,1028457510)+W(7,1041822001,1040878843,-1106259483,-1112399171);sum2=W(0,1022830461,-1117997331,1037270083,1023767946)+W(1,1021246145,-1110014342,-1125616185,-1130403951)+W(2,1015115055,-1111993293,1044158772,1025796328)+W(3,-1114703004,1036613835,1073620398,1050812248)+W(4,-1120910531,1023720090,-1076883688,-1112499600)+W(5,1015720307,-1117604953,-1087890801,1028283916)+W(6,983370825,-1120463052,1025754476,-1104874229)+W(7,-1123770073,1036937497,-1113287589,1033737696);WS(1058309838,-1101980246);
sum1=W(0,-1118965337,-1110907254,1038642111,1028903966)+W(1,-1098779704,1049643561,1038999679,-1108240479)+W(2,1049071256,-1081904943,1054751182,1040887994)+W(3,-1113399754,1042163763,1056093093,-1118832415)+W(4,1026571427,1052138696,-1083956910,1046797612)+W(5,-1110569018,-1106220306,1050507993,-1104697276)+W(6,-1131332475,1025191299,-1146247429,-1123883748)+W(7,-1128371676,-1129449041,1030864044,1017502086);sum2=W(0,-1137655511,-1111106723,1035105104,-1112318930)+W(1,1043191716,1033166752,-1112822728,1027572041)+W(2,-1121349336,1033268708,-1104857525,1035699332)+W(3,-1097517035,1052576386,1055574555,-1097542777)+W(4,1046822141,-1107318253,-1114990789,-1110157019)+W(5,-1129223371,-1102887232,-1121581721,1031007843)+W(6,-1116759551,1040601750,-1152414880,-1157281192)+W(7,-1124684976,993535634,-1107957817,1025775603);WS(1063710542,-1111213649);
sum1=W(0,1039559517,1052251350,-1101160384,-1113889808)+W(1,-1110192145,1049489370,-1097695264,1031901152)+W(2,-1107309859,1058328276,-1093740712,-1104513406)+W(3,-1118762901,1061120005,-1096321197,-1097003636)+W(4,-1108199122,1049656673,-1097289639,-1112381384)+W(5,1037245627,1033876357,-1114972772,-1176476024)+W(6,-1139769966,1041987905,-1102516745,1022802380)+W(7,1035326852,1045428971,-1103522251,-1115185874);sum2=W(0,1026803387,-1115186477,999853755,-1112425236)+W(1,1021750253,1031459540,1031446318,-1106593609)+W(2,1040812059,-1116326399,1058720440,-1086524651)+W(3,-1107480079,1040651083,1071698983,-1075753828)+W(4,1041131835,1020594503,1051128601,-1096266051)+W(5,-1115082464,1033768858,1034660038,-1108942599)+W(6,1006187407,-1132516997,1027131696,-1123360193)+W(7,1001155939,1015478283,1041372466,-1104453127);WS(1039772272,-1082982873);
sum1=W(0,1039127452,1049032497,-1098139952,-1155633625)+W(1,-1106264016,1053169593,-1088020664,1043520647)+W(2,-1104546353,1060522592,-1087153807,1040400554)+W(3,-1145518233,1056693961,1038834197,-1139907193)+W(4,1041713673,-1095982984,1053429837,-1104883452)+W(5,1044410893,-1088607916,1048228018,-1103034636)+W(6,1039725795,-1099512929,1030077856,-1134131855)+W(7,1007790526,-1120546088,-1130616150,1012687882);sum2=W(0,1032987173,-1092902636,1027660911,1032111389)+W(1,-1102803435,1037122437,1039508875,-1101516234)+W(2,-1097110538,-1083842457,-1115097563,1001644292)+W(3,-1101871105,1067610414,1067552095,-1104358647)+W(4,-1101555589,1033006847,-1096151174,-1145661076)+W(5,-1123533577,1041814167,1026567371,-1104681426)+W(6,-1098769512,1045724867,-1107225085,1020958965)+W(7,1048796624,999019252,-1105667947,1028203943);WS(-1101412664,1073047832);
sum1=W(0,-1113880945,1059007377,-1091904865,-1133362719)+W(1,-1123950537,1047579477,-1097814305,-1131741454)+W(2,-1109995975,1060416389,-1087199740,1032803377)+W(3,-1123565085,1056063051,-1092124214,-1113780884)+W(4,-1123728428,1046383171,-1099567891,-1113889390)+W(5,1035385983,1040643140,1038341800,-1126485237)+W(6,-1115318676,1033389702,-1119557930,1012558775)+W(7,1010675502,1041003725,1042882861,-1096461162);sum2=W(0,1013686761,1030949359,-1109223248,-1132915573)+W(1,-1123503757,1039110679,1035635962,996209923)+W(2,1035262859,-1105775253,-1106751414,1029135163)+W(3,-1115490710,1027204409,1057425426,1070858778)+W(4,1025861040,1019519396,1043312829,1067133266)+W(5,980681483,-1111394964,-1098000154,-1098902818)+W(6,-1125276038,1024413043,1051287795,-1083268694)+W(7,-1129892230,-1126757058,-1103421662,-1073095921);WS(-1103532344,-1105840701);
sum1=W(0,-1106756472,-1105825052,1050195304,1044840709)+W(1,-1106322913,1053932942,1007328528,-1104890465)+W(2,1029810954,-1086676361,1057202097,-1144507642)+W(3,-1096389739,-1098358914,1054492326,-1098185309)+W(4,-1116067305,1054020609,-1093369370,1032208700)+W(5,1035916925,-1096691570,1012599092,1048715303)+W(6,-1105566449,1051257001,1027855335,-1100267787)+W(7,1034505108,1026552303,-1101687900,1050640157);sum2=W(0,-1111707317,-1101137684,-1116414033,-1103752872)+W(1,-1119262447,-1109186725,-1107841286,1034593530)+W(2,1037989791,1049211868,1056722210,-1110917586)+W(3,1056036881,-1099242284,-1094543747,1049861706)+W(4,-1105645897,1038198606,1053421235,1030171051)+W(5,1006194414,-1118866635,-1104714858,-1103907620)+W(6,-1146663095,-1109483964,-1120693058,1032413269)+W(7,-1129479912,-1114787638,-1115357885,1029169157);WS(1045178680,-1115117954);
sum1=W(0,-1102680211,1048681528,1019008549,1008490315)+W(1,-1123018420,-1113607536,1040296293,1012835273)+W(2,-1116849368,-1092105355,1035615004,1027033246)+W(3,1024407336,-1093530556,1061339424,-1128145511)+W(4,-1107241006,-1096193779,1057711678,-1103222073)+W(5,1026392201,-1102060551,1055864515,-1110547491)+W(6,-1107918421,-1102337510,1045891981,-1110097884)+W(7,-1123314455,-1095199752,1052562824,1020395952);sum2=W(0,-1108321996,-1096948503,-1112108000,1026091852)+W(1,-1115537892,-1104693583,-1112710060,1022753169)+W(2,-1106228104,1047339287,-1126080161,-1120501740)+W(3,998645667,1055675007,1051246853,-1105262859)+W(4,-1112292909,1049114511,1041989299,-1123292948)+W(5,1035781218,-1100682049,1025978716,-1139782977)+W(6,-1111036660,1032758858,1034053890,-1111667328)+W(7,1018530825,-1113969306,-1113712936,1033000622);WS(1044590904,1058699692);
sum1=W(0,985175380,-1092606720,1051210502,1009220799)+W(1,1034192409,-1090621088,1050384326,-1109361592)+W(2,1020554347,-1093618783,1055009987,-1117059707)+W(3,1024014533,-1113905855,1062574818,-1128567457)+W(4,-1115433194,-1096920415,1054554325,1015981863)+W(5,-1128687821,-1112503613,1031218808,1039114097)+W(6,1008304190,-1100279725,-1105751509,-1127205548)+W(7,-1115445028,-1101027255,-1144235755,1035507338);sum2=W(0,1036009101,-1108619644,1010492213,-1131279719)+W(1,-1117283755,1041337919,-1100684466,1035041542)+W(2,1033667347,1012813669,1015579759,-1124020763)+W(3,-1107239966,1053310286,1056064408,1025470531)+W(4,1034685217,-1103814148,1050883237,1032198922)+W(5,-1128406639,1029066827,-1113069964,-1104788458)+W(6,-1123321687,-1109499964,-1098878001,1024066141)+W(7,-1125402335,-1123197815,-1096911819,-1108347132);WS(1044030776,-1089132931);
sum1=W(0,1034269487,-1093699058,1045160768,1040395197)+W(1,1032883970,-1097458090,1050995424,-1135242887)+W(2,1042439154,-1086092656,1057188990,1040422743)+W(3,1044751430,-1078975458,-1096290982,1048952172)+W(4,1019707982,1035194756,1032938655,1042217766)+W(5,1041434446,1038040390,1043682915,1043586045)+W(6,-1133288904,-1131544335,1022768458,1029073256)+W(7,-1128708109,-1101499019,1043305900,1044718778);sum2=W(0,1043294282,-1107262777,-1132728616,-1112978295)+W(1,-1127265324,-1107127922,-1133435576,-1101649503)+W(2,1035036911,1048700262,-1115280193,-1142433873)+W(3,1051203976,-1114081637,1060204569,-1138065032)+W(4,-1092441683,1027047222,-1096051714,1049542158)+W(5,1037063919,-1087538045,1059699424,1027406094)+W(6,-1095318743,1043898666,-1091030613,1036599707)+W(7,-1096741875,-1114635611,1057805441,-1117298502);WS(-1083489614,-1078579141);
sum1=W(0,-1113694287,-1091060438,1048678744,1022130309)+W(1,1048897616,-1104759380,1055607032,1045345264)+W(2,-1104500498,-1089217572,1025763911,-1098656951)+W(3,1029397720,-1096433234,1056656214,1045280313)+W(4,1039983475,-1090900481,1055730826,1003335600)+W(5,-1099529286,-1103761763,1039576037,-1104729181)+W(6,1047818144,-1126261903,1050842685,1045845834)+W(7,-1100400745,-1098862766,1044462332,-1124798927);sum2=W(0,1034867092,-1113896283,-1089397746,1053130734)+W(1,1036831152,1008734783,-1143881728,1048547317)+W(2,-1155378720,-1107821706,-1090933436,1050664536)+W(3,1050005016,1036439980,1067046868,-1081990202)+W(4,-1109019109,-1105188391,1074023168,-1073616958)+W(5,-1107857756,-1103852014,1073004488,-1073650181)+W(6,1025727369,-1113326142,1071596064,-1078582463)+W(7,-1105627363,1036502992,1068047188,-1079035066);WS(-1123566816,-1118788492);
sum1=W(0,1034266605,-1131696345,-1102436480,1029920799)+W(1,-1136553988,1054570946,-1101485920,1027694719)+W(2,1032767842,1043367745,-1093672570,1029228634)+W(3,-1119057557,1057910725,-1081257723,1038070160)+W(4,1032596498,1051309065,-1104247863,1041012541)+W(5,-1138237144,1050053561,-1097237249,-1104490509)+W(6,1034235800,1044754161,-1100737384,1036672371)+W(7,1038972738,1047609962,-1118734125,-1101643609);sum2=W(0,1001205015,-1108935456,-1123729961,-1151981614)+W(1,1006355343,1048575251,1037564428,-1123825361)+W(2,1030505158,-1114918170,-1096130861,1015236500)+W(3,-1119701641,-1088419213,-1068662368,-1095410362)+W(4,1039794598,1032736312,1076967646,1049774729)+W(5,-1107202062,1045905661,1068403675,-1105335733)+W(6,1026836118,-1116946341,-1104305708,1050153445)+W(7,-1115440174,1003805295,-1124006983,-1103176791);WS(-1103567160,1051728620);
sum1=W(0,1022317012,1037463598,-1094952698,1033922872)+W(1,-1105517764,1027268637,-1107670055,1024776175)+W(2,-1109296554,1052072875,-1103880757,1038888053)+W(3,1030946149,-1094107172,1052944567,1043766492)+W(4,1032988986,-1087396213,1057943536,-1110506946)+W(5,-1117957958,-1098739651,1052382091,-1108829569)+W(6,1025729823,-1104965205,1036164793,-1132271979)+W(7,1009731405,1017302004,1041821631,1015545129);sum2=W(0,1031290011,-1127050317,-1113481669,-1080536402)+W(1,-1114551402,1026829489,1042490649,-1076466135)+W(2,-1137203270,1032334734,1043198364,1038797044)+W(3,1025723227,-1098446681,-1127701979,1074254195)+W(4,1020823723,1041359246,1057793899,1035340712)+W(5,-1107112701,1041376772,-1100591458,-1118262367)+W(6,-1156747895,1034398482,-1114292550,1013380262)+W(7,-1140368490,-1104694439,1037536680,1032104302);WS(-1106439480,1029090439);
sum1=W(0,1034559195,1042655458,-1102396839,1026400220)+W(1,-1151887836,1030625962,-1115609614,1035325646)+W(2,1020849475,1059377738,-1089162129,1042909598)+W(3,1042053132,-1084013087,-1083731653,1039293086)+W(4,1043127920,-1107145304,1052971191,1029716960)+W(5,1043814293,1032281331,-1107154457,1024778063)+W(6,1037260390,1040913704,-1113717087,1028666946)+W(7,1043715864,1033172451,1017680531,-1130742978);sum2=W(0,-1129107524,1021999108,1022835844,-1129901940)+W(1,-1123636938,-1148550480,1016982596,-1140398984)+W(2,-1116921954,-1104180688,1016773924,1030858450)+W(3,1035143287,1058583951,1054454385,-1117386658)+W(4,1036996009,-1112895549,-1097314323,-1108156993)+W(5,1026655402,-1116180274,-1099699990,-1118751234)+W(6,-1117010042,-1131502740,-1132536424,1016259828)+W(7,-1126794884,-1138164712,-1129763396,-1117013506);WS(1048151864,1059242544);
sum1=W(0,-1122367849,-1097114939,1043794348,1026875087)+W(1,-1121466768,-1097911384,1033810391,1014185912)+W(2,1042165293,-1085899247,1063564267,-1106211614)+W(3,-1116044868,1042506911,1042284551,-1111561384)+W(4,-1105437493,1056857214,-1089674786,1040868541)+W(5,1037358179,-1105063934,1049648847,1028107682)+W(6,-1125163356,-1123578292,1021855394,-1111395274)+W(7,-1111398955,-1106114902,1045389303,1010402126);sum2=W(0,-1139648101,-1110557326,-1106733442,1039330638)+W(1,-1108856547,1041627874,-1106727608,987619817)+W(2,1015236663,1032833232,1048813377,1025349119)+W(3,-1095822659,1054902128,1055403310,-1095503796)+W(4,-1137977893,-1098765424,-1097123375,1050144719)+W(5,1038373686,-1121592121,1045561320,-1108448514)+W(6,1015865663,-1106594443,-1106386080,1041979856)+W(7,1025690243,-1117564251,1017823319,-1105901385);WS(1058511566,1043187024);
sum1=W(0,1042620242,1041476871,-1106861387,1043942651)+W(1,1027981614,1044640335,-1120607404,1040914531)+W(2,1037513401,1039039385,-1101062960,1040902562)+W(3,1050564856,-1085132912,-1089194338,1048598306)+W(4,1040390932,-1095196494,1032203084,1019897185)+W(5,1044188393,-1116362934,-1134658518,1032634704)+W(6,1032851398,-1107832665,1026497359,1027555603)+W(7,1043046140,-1105825814,-1105488567,1032742569);sum2=W(0,-1094808435,-1083260450,1041967320,1026111290)+W(1,-1132385524,-1089624726,-1102801635,1034887813)+W(2,-1110994277,-1098133391,1050258559,-1123786474)+W(3,1039748829,1063143581,1037743779,1033106845)+W(4,1038866141,1043371703,1048943341,-1110363077)+W(5,1012861192,1040218148,-1112998265,-1121754906)+W(6,1030487914,1012758152,1031702418,1012203560)+W(7,-1132742376,1052570990,-1105604919,-1111765769);WS(-1087236686,1061665912);
sum1=W(0,-1115274057,1023071688,-1107980923,-1119301463)+W(1,-1116162424,1030200068,-1101866270,-1128116268)+W(2,-1104461343,1054050807,-1092884195,-1109238785)+W(3,-1093387666,1067462106,1056570668,-1095571507)+W(4,-1113556238,1050597447,1044256537,-1103733247)+W(5,-1115159031,1031104576,-1106234576,-1111522325)+W(6,-1126942285,-1121547516,-1128835891,-1111458030)+W(7,-1121543315,1042315272,-1114796114,-1109780718);sum2=W(0,-1127633710,1024134807,-1114424195,-1109129714)+W(1,1024854732,1020748524,-1098546148,1025355297)+W(2,-1123781128,-1117094752,-1079772750,-1102118069)+W(3,1040493279,1065417820,1059484680,-1114766469)+W(4,-1105896535,1047826025,-1107504040,1033237727)+W(5,1033983514,-1102101577,1049649199,-1154145757)+W(6,-1122459292,1040101538,-1105983778,1012710689)+W(7,-1120616672,-1124130304,1041220419,-1123999628);WS(-1092106140,-1084163121);
sum1=W(0,1036347305,1049849489,-1101083230,-1106738110)+W(1,1016904817,1040213041,-1152694122,-1115216475)+W(2,1034414494,1056746079,-1083169173,1039797369)+W(3,1040590819,1048812489,-1107117385,1022569263)+W(4,1047670567,-1084779712,1051667767,-1112982247)+W(5,1030378702,1040726752,-1109066592,-1125038036)+W(6,-1114654031,1033236350,1024925978,1025136605)+W(7,1037868673,1034988241,-1107106473,-1146668256);sum2=W(0,-1144361879,-1111008682,-1092072719,1021883158)+W(1,-1128843246,-1134810723,-1121102479,-1116668390)+W(2,1005924247,1041181160,1045581242,-1109114373)+W(3,-1104940693,1054697191,1046555600,-1113715104)+W(4,-1123234701,1052731012,-1103970223,-1128555074)+W(5,1030348431,1042931729,-1104348933,1032936433)+W(6,1032437115,-1112071203,-1113690885,-1136719027)+W(7,1024671661,-1111460488,-1129885552,-1114960949);WS(1058637774,-1109876822);
sum1=W(0,-1123254812,1042623060,-1126486401,-1112485473)+W(1,1041301297,-1105094644,-1111052512,1037949088)+W(2,-1108082435,1059472952,-1094910408,1016105496)+W(3,-1113241451,1043969956,-1094009726,1038892497)+W(4,-1110973875,-1113269955,1058531737,-1093047519)+W(5,1027216056,1026816394,-1100061186,1032398170)+W(6,1014894339,-1130602892,1032486130,-1128303438)+W(7,1019588394,1026167148,-1117291247,1021704844);sum2=W(0,1019183838,-1103677237,1041385745,-1115238116)+W(1,1031923668,1026573624,1025625867,1024201143)+W(2,1049015983,-1101357077,-1095136476,1024442030)+W(3,-1096362417,1060010174,-1096248497,-1122837727)+W(4,1005830618,-1122620605,-1115221092,1034369966)+W(5,1036998273,-1106684685,1049273019,1031554545)+W(6,-1119396253,1023743335,-1112424814,1004099770)+W(7,-1125844722,970656667,1011280453,1010302645);WS(1068382951,-1145853862);
sum1=W(0,-1109092968,-1104283584,-1126224104,-1142984099)+W(1,-1120835030,-1104742016,1048835390,1035504970)+W(2,1015957108,-1087137628,1060142968,1044651720)+W(3,1033165317,-1082841532,1050512116,1036256010)+W(4,1015780402,1048723479,1050625794,1040271692)+W(5,-1098982451,-1119342334,1046183055,-1112268532)+W(6,-1106789039,1037068029,1033167819,-1115364877)+W(7,-1105810191,998682871,1042826568,-1113754717);sum2=W(0,1042289605,-1105845074,-1105090355,1041479887)+W(1,-1123754179,1032442894,-1106552079,1028813354)+W(2,1040865617,-1090127653,-1075116096,-1087510643)+W(3,1025996190,1055606718,1073431719,-1084272058)+W(4,-1100913998,-1104101067,1067916428,1045036562)+W(5,-1118459936,1026136504,1042119939,-1131666845)+W(6,-1114401734,1031986833,-1112990087,1021173748)+W(7,-1118182115,1045409779,1031635830,-1131440550);WS(-1115823328,-1115141930);
sum1=W(0,994860217,-1096937968,1034643656,1022968545)+W(1,1043355533,-1093401724,1045563268,-1100277972)+W(2,1046651158,-1082957735,1056739037,-1106135459)+W(3,1031967699,1057829358,1053028032,-1113373017)+W(4,-1112906011,1054780763,-1085595451,1036473238)+W(5,-1139800861,1049387203,-1100812438,1042166401)+W(6,1032268536,1029694230,-1112691098,-1109328859)+W(7,1021673189,1032667294,-1163065290,1026417494);sum2=W(0,1041009418,1006794492,1023178506,-1126244586)+W(1,-1106230161,1034312638,-1120362931,1021996758)+W(2,-1113994011,-1108126219,-1105213924,-1131146954)+W(3,-1100787264,1060460225,1054015707,997147503)+W(4,-1102450993,-1119222967,1053508358,-1107185372)+W(5,-1114680808,-1097084093,-1133314452,-1126416406)+W(6,1031764893,-1125377404,-1141774536,-1126617106)+W(7,-1145068408,-1105852265,-1120752408,-1131039214);WS(1044911928,1063248560);
sum1=W(0,-1117210934,-1089987573,1050931427,-1154913199)+W(1,1045807559,1006551364,1049202419,1049427019)+W(2,-1116245664,-1085623154,1044690392,-1098224261)+W(3,-1122601008,-1098705597,1056494849,1043742399)+W(4,1041679280,-1089608778,1054654497,1009817082)+W(5,-1102494868,-1098692501,1047881833,-1102952115)+W(6,1044187563,1040126000,1043119951,1048685800)+W(7,-1101059428,-1100421777,1043071666,-1132265536);sum2=W(0,-1110897864,1031814971,1060526454,-1090228093)+W(1,-1104703066,-1126406622,1034850394,-1097166620)+W(2,1039476246,-1112535334,1060516426,-1091926928)+W(3,-1102025112,-1088994686,-1088701567,1063814816)+W(4,1041770976,1050082866,-1072347435,1074296249)+W(5,1044782005,1038057456,-1075073775,1073862535)+W(6,-1112640404,1029663347,-1077197270,1067261757)+W(7,1045848501,-1098794387,-1081012351,1067785227);WS(-1105546040,1026157880);
sum1=W(0,1040950836,1040614249,-1102499357,1036650571)+W(1,1036866652,1043435937,1032157499,1032871003)+W(2,1045419231,1048836647,-1088963702,1035867609)+W(3,1057171433,-1092874056,-1078642173,1040635958)+W(4,1039696013,1049109967,-1094603626,1039966133)+W(5,1040737235,1037560064,999044599,1035782037)+W(6,1031337694,1039556030,-1107844556,1034875342)+W(7,1043417390,1020658754,-1101965321,1029450491);sum2=W(0,999804672,1033414560,-1131242272,-1111239120)+W(1,965076992,-1142972544,-1152459008,-1114613368)+W(2,1017997216,-1117537424,1043660652,1024438240)+W(3,-1113573416,-1080122522,1068973644,1009242816)+W(4,1015814944,-1116987776,-1113471168,1026341216)+W(5,1013150208,1009041344,1023678672,-1111376032)+W(6,1004325632,1030258512,-1115573696,-1124670336)+W(7,-1116017408,-1123867424,1025739248,1011147520);WS(-1081027239,1060388068);
sum1=W(0,1040945153,1049191505,-1103567931,-1142725077)+W(1,1018532824,1052335227,-1106690587,-1126830164)+W(2,1048158700,1053224518,-1098210230,1044049241)+W(3,1050078256,-1089652372,-1079677805,1037048166)+W(4,1043330564,1050009062,-1090769236,1037549983)+W(5,1045983912,1019623144,-1102526621,-1124021470)+W(6,1034126717,1043374892,-1113976903,1031972104)+W(7,1042366848,1037373643,-1106920486,1000910717);sum2=W(0,1029289565,-1119356133,-1126159585,-1119814653)+W(1,1023484285,1031916514,-1111485988,-1133461586)+W(2,1041097307,-1120749829,-1121314077,-1112201820)+W(3,1044843621,1057057740,1024531885,1001931237)+W(4,-1101664529,1055633817,-1102656055,1035253182)+W(5,-1108647964,-1098024997,1016983721,1019582313)+W(6,-1111945130,1038083406,-1105960100,1011319026)+W(7,-1129898257,-1101101054,1022769465,-1110859200);WS(-1121436896,-1083449266);
sum1=W(0,-1131437006,1057845458,-1096100393,-1112818966)+W(1,-1126965659,1026072602,-1106937331,1025271436)+W(2,-1106898372,1058188821,-1089458543,-1120770471)+W(3,1049661628,1047051462,-1093909527,1039868950)+W(4,-1110051320,1036301673,-1105302990,-1101852248)+W(5,1048826500,1049513187,-1097831955,1048680544)+W(6,1018834023,1026266705,-1115312055,-1111779257)+W(7,1030351624,1043516478,-1094725407,-1137214404);sum2=W(0,1025140224,-1118806788,-1126785121,1031495588)+W(1,1016993788,1030590564,-1118559458,991152164)+W(2,-1106156741,1042721449,-1106137914,1038491925)+W(3,-1085967118,1078987048,-1100137345,1040984057)+W(4,-1070014283,1078555235,1044823121,-1111978905)+W(5,-1066270592,1069325982,-1105174392,1030579932)+W(6,-1089828448,1051485796,-1121082393,-1113499951)+W(7,-1115300709,1026006822,1011662011,-1120641633);WS(1060473294,-1125032523);
sum1=W(0,-1118381578,1043924207,1028842287,-1103983036)+W(1,-1131528546,1048790648,-1094915206,1032416951)+W(2,-1103035725,1057928103,1048586166,-1131359957)+W(3,1044891665,-1096003632,-1089668066,1041536420)+W(4,1017562024,-1104437021,1048997587,-1119623443)+W(5,1038728371,-1127678449,-1106021950,1026802338)+W(6,1013193724,-1138265298,1016196772,-1112764523)+W(7,1017619335,1019650740,-1112334062,1028850580);sum2=W(0,-1124013145,1023871771,1041717973,1027246941)+W(1,-1154979909,-1104183315,-1104961174,-1105906795)+W(2,-1113455493,1024353365,-1071159846,-1114760758)+W(3,1042673063,-1099433949,1075222357,1048045634)+W(4,1009341589,1037029004,1061754151,-1101645527)+W(5,-1131887235,-1106752952,-1106459992,1027783079)+W(6,-1126494367,-1136822537,1037905746,-1130069351)+W(7,-1120394460,-1135604889,1020599743,1023779471);WS(1063175758,1049951270);
sum1=W(0,1051934199,-1084051495,1040719576,1028219745)+W(1,1041620825,-1091045702,1046456792,1028165760)+W(2,1053157077,-1089200998,1054477181,-1110307566)+W(3,1019501037,-1103613676,1050464826,1037889601)+W(4,-1121035141,-1103906809,-1098419444,1045652053)+W(5,1024394007,1042850683,-1097805325,1054554722)+W(6,1034798936,-1117239270,1011564046,1031152711)+W(7,999909159,-1106705027,-1091232034,1056053333);sum2=W(0,-1091471926,1062079447,1055700238,1015596856)+W(1,1042259987,-1095572989,1041645665,1033532620)+W(2,-1103057728,-1089203271,1037140407,1035045090)+W(3,1049412228,-1092861102,-1093629070,1042934527)+W(4,1044973062,1034556296,-1095940003,1032040702)+W(5,-1116401558,1047552828,-1106623325,-1106239816)+W(6,1011000463,-1110031497,-1107294450,1033073048)+W(7,-1130123924,1051271629,1053844390,-1095799213);WS(-1085388366,-1090694979);
sum1=W(0,-1123787314,1044273497,-1108110651,-1115475932)+W(1,-1119481145,-1130943626,1041576542,-1117135031)+W(2,1032777214,1047368143,-1087220302,1040347561)+W(3,-1112850502,1059845268,1027588771,-1101064470)+W(4,1041751591,-1095680144,1036323946,1037523789)+W(5,-1125429276,1039407200,-1111657568,-1126225621)+W(6,-1140788444,990533574,1021334836,-1134357621)+W(7,-1113892940,1032644049,-1143449895,-1109271006);sum2=W(0,-1107190004,1037736456,-1125693587,-1120404934)+W(1,1013881877,-1105376838,1040619572,-1122228614)+W(2,-1118295314,-1123416196,-1082924015,1051908042)+W(3,-1121103222,1042717593,1068021664,-1087341114)+W(4,-1127822751,-1115549939,1016978358,1042189807)+W(5,-1115317828,1043660085,-1108863865,-1125959243)+W(6,-1126179247,-1126402007,-1136349779,1038966556)+W(7,-1114801766,1040920849,-1107267301,1023515477);WS(1065904679,-1122628785);
return clamp(mstd0 + 5.0 * vsum / wsum * mstd1, 0.0, 1.0);
} // nnedi3
vec4 hook() {
vec4 ret = vec4(0.0);
vec4 samples[8];
samples[0][0] = HOOKED_texOff(vec2(-3.0, -1.0)).x;
samples[0][1] = HOOKED_texOff(vec2(-3.0, 0.0)).x;
samples[0][2] = HOOKED_texOff(vec2(-3.0, 1.0)).x;
samples[0][3] = HOOKED_texOff(vec2(-3.0, 2.0)).x;
samples[1][0] = HOOKED_texOff(vec2(-2.0, -1.0)).x;
samples[1][1] = HOOKED_texOff(vec2(-2.0, 0.0)).x;
samples[1][2] = HOOKED_texOff(vec2(-2.0, 1.0)).x;
samples[1][3] = HOOKED_texOff(vec2(-2.0, 2.0)).x;
samples[2][0] = HOOKED_texOff(vec2(-1.0, -1.0)).x;
samples[2][1] = HOOKED_texOff(vec2(-1.0, 0.0)).x;
samples[2][2] = HOOKED_texOff(vec2(-1.0, 1.0)).x;
samples[2][3] = HOOKED_texOff(vec2(-1.0, 2.0)).x;
samples[3][0] = HOOKED_texOff(vec2(0.0, -1.0)).x;
samples[3][1] = HOOKED_texOff(vec2(0.0, 0.0)).x;
samples[3][2] = HOOKED_texOff(vec2(0.0, 1.0)).x;
samples[3][3] = HOOKED_texOff(vec2(0.0, 2.0)).x;
samples[4][0] = HOOKED_texOff(vec2(1.0, -1.0)).x;
samples[4][1] = HOOKED_texOff(vec2(1.0, 0.0)).x;
samples[4][2] = HOOKED_texOff(vec2(1.0, 1.0)).x;
samples[4][3] = HOOKED_texOff(vec2(1.0, 2.0)).x;
samples[5][0] = HOOKED_texOff(vec2(2.0, -1.0)).x;
samples[5][1] = HOOKED_texOff(vec2(2.0, 0.0)).x;
samples[5][2] = HOOKED_texOff(vec2(2.0, 1.0)).x;
samples[5][3] = HOOKED_texOff(vec2(2.0, 2.0)).x;
samples[6][0] = HOOKED_texOff(vec2(3.0, -1.0)).x;
samples[6][1] = HOOKED_texOff(vec2(3.0, 0.0)).x;
samples[6][2] = HOOKED_texOff(vec2(3.0, 1.0)).x;
samples[6][3] = HOOKED_texOff(vec2(3.0, 2.0)).x;
samples[7][0] = HOOKED_texOff(vec2(4.0, -1.0)).x;
samples[7][1] = HOOKED_texOff(vec2(4.0, 0.0)).x;
samples[7][2] = HOOKED_texOff(vec2(4.0, 1.0)).x;
samples[7][3] = HOOKED_texOff(vec2(4.0, 2.0)).x;
ret[0] = nnedi3(samples);
return ret;
} // hook
//!DESC NNEDI3 (combine_y, nns128, win8x4)
//!HOOK LUMA
//!BIND HOOKED
//!BIND nnedi3_int
//!HEIGHT 2 HOOKED.h *
//!OFFSET 0.000000 -0.500000
//!WHEN HOOKED.h OUTPUT.h / 0.707106 <
vec4 hook() {
vec2 dir = fract(HOOKED_pos * HOOKED_size) - 0.5;
if (dir.y < 0.0) {
return HOOKED_texOff(-dir);
} else {
return nnedi3_int_texOff(-dir);
}
}
//!DESC NNEDI3 (double_x, nns128, win8x4)
//!HOOK LUMA
//!BIND HOOKED
//!SAVE nnedi3_int
//!WHEN HOOKED.w OUTPUT.w / 0.707106 <
float nnedi3(vec4 samples[8]) {
float sum = 0.0, sumsq = 0.0;
for (int i = 0; i < 8; i++) {
sum += dot(samples[i], vec4(1.0));
sumsq += dot(samples[i], samples[i]);
}
float mstd0 = sum / 32.0;
float mstd1 = sumsq / 32.0 - mstd0 * mstd0;
float mstd2 = mix(0.0, inversesqrt(mstd1), mstd1 >= 1.192092896e-7);
mstd1 *= mstd2;
float vsum = 0.0, wsum = 0.0, sum1, sum2;
#define T(x) intBitsToFloat(x)
#define W(i,w0,w1,w2,w3) dot(samples[i],vec4(T(w0),T(w1),T(w2),T(w3)))
#define WS(w0,w1) sum1 = exp(sum1 * mstd2 + T(w0)); sum2 = sum2 * mstd2 + T(w1); wsum += sum1; vsum += sum1*(sum2/(1.0+abs(sum2)));
sum1=W(0,-1106336704,-1134422686,-1097058997,-1096794255)+W(1,-1096428577,-1108910446,-1110459731,-1101174078)+W(2,-1104338237,-1108550970,1036063029,1068454954)+W(3,1045547931,-1102009308,-1122481515,1017740065)+W(4,1041734649,-1135080854,1053379177,1068510503)+W(5,-1114733521,-1146436468,-1107441476,-1113618698)+W(6,-1112016931,-1117701445,-1099451832,-1092648385)+W(7,-1101312270,-1118387353,-1118789516,-1107281979);sum2=W(0,-1107960738,1022891960,-1112828174,-1099542471)+W(1,1028527356,-1124169384,1003609248,1019646072)+W(2,1034572820,1003346080,-1096749055,1067566060)+W(3,-1090311143,1028295012,-1101382023,-1102277943)+W(4,-1105088633,-1103397515,1056062200,-1127174872)+W(5,1048792675,-1106700271,1033154740,1037356874)+W(6,-1147785184,1035529310,-1105585021,1034766166)+W(7,-1117109292,-1116900804,-1121486356,-1114899026);WS(-1075683047,-1087125913);
sum1=W(0,1042687663,1034752002,1020877136,1043598702)+W(1,1032834596,1049059763,1041786741,1050972591)+W(2,1052977914,1046022844,1051043629,1049374510)+W(3,1044576234,-1108783446,-1105784362,-1089957133)+W(4,-1087267578,-1097639380,-1087388173,-1095656786)+W(5,-1108370107,-1101488315,-1111228387,-1108747496)+W(6,1041384601,1034807969,1037740431,1044538321)+W(7,-1113942663,1043415765,1011031587,1034104676);sum2=W(0,-1129327146,-1149557934,1027469999,-1116270499)+W(1,-1107094547,-1114668504,-1136313139,-1115408970)+W(2,-1112916736,-1120018795,-1105442406,1056936993)+W(3,1036431709,1029410453,-1126491682,-1112281372)+W(4,-1109246006,1012425107,1044505132,1054092693)+W(5,1015080154,-1102188513,-1123974759,-1115235380)+W(6,-1168639863,-1122303521,-1114911422,-1109477794)+W(7,-1122292075,1038663029,-1124857486,1004657207);WS(1042212664,-1102203684);
sum1=W(0,-1140902818,1019874102,-1138465404,1041713132)+W(1,1031911135,1032244040,-1122713961,1032066151)+W(2,1040147851,-1104962202,-1102798136,-1085739950)+W(3,-1090423514,-1096835716,1015091005,-1100137137)+W(4,1035472140,1045102086,1044852023,1052255697)+W(5,1050093153,-1114874577,-1125530488,1025859399)+W(6,-1111794429,1033944684,-1122108180,1042129278)+W(7,1026181805,1045351411,1045226448,1037723887);sum2=W(0,1025219442,-1119436548,1041363772,1026037858)+W(1,-1106963956,-1148187164,-1115265228,1027834104)+W(2,-1109152196,-1122141349,1032935700,-1095545125)+W(3,1029288712,1048235476,1017807431,-1124373883)+W(4,1026944460,1040314652,-1124096755,-1132954458)+W(5,1063106013,1044093468,-1119277141,-1115291573)+W(6,-1136900198,-1112897189,-1144192892,1046665648)+W(7,-1112667488,-1091150222,-1098670428,-1099776205);WS(-1106435384,1038338229);
sum1=W(0,1040095954,1019822615,1037825128,1041126536)+W(1,1042659628,1046281616,1025627498,1052688116)+W(2,1057302312,1048464174,1048602738,1046177110)+W(3,-1113571175,1010729037,-1116720143,-1090676327)+W(4,-1085504617,-1109673285,-1088007186,-1089584127)+W(5,-1112427435,-1099904421,985851280,-1109333660)+W(6,1038469973,1008999077,1047759857,1042217259)+W(7,-1122205838,1042535855,1020820192,1034203799);sum2=W(0,1016257202,1025056091,-1123344133,-1117490597)+W(1,-1139226916,-1121712633,1032149092,1018740994)+W(2,1059204215,1059357388,-1096239491,-1080318626)+W(3,-1097775023,-1121076469,-1108589001,1042934709)+W(4,1078138204,1057901024,-1075026282,-1073900782)+W(5,1041808545,1040778731,1040543247,1013253724)+W(6,1045786159,-1115583727,1040463834,1043123901)+W(7,1021989454,-1105966927,1015040126,-1147555881);WS(-1079558823,-1098708322);
sum1=W(0,-1107155318,1025234303,1015859078,1036194249)+W(1,-1109510417,-1106597869,-1106784003,-1107821257)+W(2,-1102044491,-1098872409,-1087610848,-1086405173)+W(3,1049149960,-1113006787,1034815041,-1109243348)+W(4,-1157836704,1050456336,1055919296,1051086989)+W(5,1049231261,1047976577,1037659280,1045770027)+W(6,1018716763,1032647774,1043448582,1041211303)+W(7,1032229161,-1113988824,-1114873522,-1115826050);sum2=W(0,-1115121954,1012713185,-1120959275,979525395)+W(1,1031308048,1023425822,1008898041,1015643115)+W(2,1038073794,-1114116718,1048906430,-1089285214)+W(3,1044939824,960279117,-1114246838,-1116674868)+W(4,-1128914993,1041575276,1074552079,-1076455267)+W(5,-1081125046,-1109266711,1028966618,-1116558128)+W(6,-1116577465,-1124395325,1055266270,1060162115)+W(7,-1098098687,1021768571,-1124862202,1013382601);WS(1045132600,-1120782135);
sum1=W(0,-1105751784,-1105178898,-1104184899,-1114219853)+W(1,-1110381909,1038688878,-1129240105,1028338913)+W(2,1057393815,1048859946,1059464001,1046945589)+W(3,-1115358437,-1101266388,1006928425,1001553277)+W(4,-1105555137,-1097544977,-1093321826,-1096850414)+W(5,1045680426,1054674458,1040711722,1051440502)+W(6,-1117651397,1030868229,-1113548192,-1114482291)+W(7,-1100710867,-1101910270,-1109195062,-1106616547);sum2=W(0,1017265392,-1109811903,1023756444,-1113627340)+W(1,1014378799,-1145950526,-1129429444,1013677319)+W(2,1041015042,1031690548,1041543835,1061785433)+W(3,-1112539854,1033767962,-1111764061,-1098545742)+W(4,-1100279165,-1110095441,-1121800962,1052269299)+W(5,1027655784,-1103181542,-1110834939,-1106577514)+W(6,1015388608,-1118750728,1018680528,-1143924414)+W(7,-1099334823,1020584168,-1108053853,1036964648);WS(1052573852,-1122511817);
sum1=W(0,-1122539822,1036520122,-1150669710,-1131456914)+W(1,1027717464,1032118773,1021054902,1030809195)+W(2,-1107197216,-1104137920,-1095755763,-1089160552)+W(3,-1090293588,-1090056564,-1092174087,-1086001910)+W(4,-1123108403,1038549849,1032946604,1050538028)+W(5,1052989852,1057974832,1053464075,1057808582)+W(6,1051517474,1023654291,1039184399,1041388597)+W(7,-1168884669,1033029075,1028526105,1041880934);sum2=W(0,-1085894681,1038192816,-1098445483,-1102898046)+W(1,1008806191,1050638036,-1102617523,1057325981)+W(2,-1108201039,-1090848333,1052221636,1071505414)+W(3,-1098981857,-1086351349,-1096799400,-1088620184)+W(4,1070882268,-1093216289,1067999858,1073865984)+W(5,1058878464,-1083525828,-1107159037,-1083206959)+W(6,-1081052443,-1102549623,-1087793608,-1090403840)+W(7,-1095780376,1055133376,-1096503933,1053790412);WS(-1073219892,-1080326418);
sum1=W(0,-1114077580,-1142635506,-1142955026,-1123237842)+W(1,1038107057,-1103324917,1026598572,-1095875035)+W(2,-1101602915,-1103425331,-1090278522,-1092662145)+W(3,-1091646784,-1114692451,-1101848592,1038718196)+W(4,1057495924,1053716920,1055741332,1051447237)+W(5,1052494629,1049044089,1043005848,1047828379)+W(6,-1151047116,-1114784094,-1111276924,-1121668701)+W(7,1000704387,-1109204280,1010568075,-1156952092);sum2=W(0,-1121663397,-1116542136,1042431779,1037730633)+W(1,1010053773,-1137348615,1028087910,-1119025600)+W(2,-1095443331,1050195534,-1123573301,-1100504352)+W(3,1043186658,-1102861372,-1110454800,1040229501)+W(4,-1067370736,-1071776975,1068672794,1077012119)+W(5,1070664889,1045361006,-1123945395,1027642294)+W(6,1005231721,974104521,-1111985184,1047585075)+W(7,1016528922,-1109020232,1037668055,-1117277443);WS(-1130027456,1047744266);
sum1=W(0,1030328637,-1100312969,1036569044,1044449278)+W(1,-1106699970,1046212150,-1104762293,-1124975021)+W(2,-1103440100,1043447132,-1096543805,-1093151398)+W(3,1024264999,-1115860524,1041344218,1032410566)+W(4,1050534604,1038395889,1037345619,-1106526388)+W(5,-1115006287,1035372917,980910400,1044066628)+W(6,-1130350917,-1105733872,1043114871,1022399622)+W(7,1020228332,1024836117,-1123108872,-1112803412);sum2=W(0,1029880722,-1098453144,1029103498,1067660000)+W(1,-1094604015,1046293202,-1104816365,-1117927817)+W(2,1033391383,1041649400,-1095624145,-1082091368)+W(3,1056223691,1027973488,1034193475,1034286113)+W(4,-1137819024,-1137377888,1040796761,-1080643124)+W(5,-1102259819,-1121978412,-1148596400,1041009105)+W(6,-1114516031,1025620716,1035240799,1066795978)+W(7,-1098376459,1036814117,-1107858514,-1114981924);WS(1049012636,1037011386);
sum1=W(0,-1108102978,1042768739,1036457352,-1105146600)+W(1,-1100621772,-1100160944,-1149100234,-1116535239)+W(2,-1097922903,-1089977373,-1083790961,1050515995)+W(3,1053649082,1044221701,1020595485,-1110188826)+W(4,1049818257,1052134241,1059747641,1062551839)+W(5,-1088576433,-1093385002,-1108848982,-1147628986)+W(6,1041216474,-1106782690,-1120768141,975424142)+W(7,1042971413,1047421135,-1142399358,1034144007);sum2=W(0,-1130376652,-1109307779,998991648,-1105231849)+W(1,-1124853008,-1110904873,1033926100,1012787248)+W(2,-1109271051,1040605589,-1117670218,1068278024)+W(3,-1099193318,1035466738,-1111928806,1025845624)+W(4,-1098570547,-1097221185,-1087670872,1068017963)+W(5,-1103240593,1049832589,1018913792,1035573068)+W(6,1029552052,-1097745138,-1101762859,-1100990121)+W(7,-1094879980,-1119653306,-1099498770,1046656503);WS(-1099128120,1074104605);
sum1=W(0,1001695642,-1114738061,-1137881464,1035838167)+W(1,1036976671,1043227732,1024532056,1041576607)+W(2,1031876531,1036082771,1049670772,1045634202)+W(3,1039176783,1044499416,-1115296143,1036111714)+W(4,-1106225286,-1127447088,-1114090766,-1084335000)+W(5,-1092101927,-1106295064,-1108352670,-1103209586)+W(6,1039516460,1037331996,1048871226,1024672505)+W(7,-1111706306,1040216275,1018355325,-1129216251);sum2=W(0,-1125983803,1026289226,1003361806,1036989304)+W(1,-1121376018,-1127516251,999276462,1020382491)+W(2,1057121124,1048908439,1042597022,-1101738899)+W(3,-1101518001,-1114490175,1032222895,-1111061815)+W(4,-1097673861,-1081617292,-1083990029,1066557847)+W(5,1050089807,1021212715,-1107462587,1048167829)+W(6,-1097055530,-1105528539,-1094090339,1060807350)+W(7,1045798092,1007168711,1021142275,1024157832);WS(1043392312,-1114334171);
sum1=W(0,1041086874,1027676176,1029494548,1038182418)+W(1,1033375641,1014428948,1016176348,1036956537)+W(2,1046571639,1051603231,-1114765098,1063881062)+W(3,1036439434,1039261900,1049353410,1039119196)+W(4,-1101297859,-1100311555,-1090719068,-1092551191)+W(5,-1093343060,-1095549099,-1102133676,-1097401399)+W(6,-1108043111,1031499310,-1123479337,1047470620)+W(7,1029157954,-1113522785,1032866554,-1108903402);sum2=W(0,1032922039,1034144522,1035186417,-1106146153)+W(1,995983013,1014708981,-1118508182,-1122673776)+W(2,-1110774431,1041464609,-1089347840,1063858171)+W(3,-1103182741,-1105498679,1046443094,-1107403517)+W(4,1024080221,1024001520,-1102975683,1062496232)+W(5,-1104694448,1034761930,-1113235807,-1126790312)+W(6,-1111786600,1038622987,-1098326560,-1094555153)+W(7,-1110476474,-1107944280,1045574278,-1119406695);WS(1055141020,1060902337);
sum1=W(0,1034435725,-1133288704,1026181508,1033934442)+W(1,1030709219,-1118188821,1027652318,1035419593)+W(2,1057965143,1052483105,1052696320,-1122504460)+W(3,1052884304,1049027177,1046782257,1045790650)+W(4,-1123568702,-1121795134,-1094115828,-1084201687)+W(5,-1093347107,-1096042081,-1098441692,-1101051195)+W(6,-1104499136,1006999415,-1153162900,1029709087)+W(7,1036285529,-1155692311,1013713298,-1111952258);sum2=W(0,1043194323,1017945729,992756489,-1117717167)+W(1,1023440269,-1108161809,1034607052,-1115924363)+W(2,-1070666261,-1075189642,1068575013,1076566585)+W(3,1056539999,-1098049115,1036076910,-1112346970)+W(4,-1098866335,-1106608294,1051129947,1049134123)+W(5,1047751107,-1097073139,1011007330,1016205049)+W(6,-1101126135,1010301074,-1107911121,1046700061)+W(7,1020103457,1026363561,1035420194,-1137869730);WS(-1090579868,1070279725);
sum1=W(0,1032329895,-1102328821,-1113203900,-1098061089)+W(1,-1105344998,1034205973,-1106552005,1041435478)+W(2,1048430680,1050349544,1052980239,1057014372)+W(3,1057962188,1038273502,1046276062,1049777060)+W(4,-1101560157,-1091335294,1039656780,-1084573078)+W(5,-1103450436,1043587871,-1098888483,1002064136)+W(6,-1129281319,1012204235,1033674783,-1115372202)+W(7,-1108117804,-1111454739,-1115265901,-1109943484);sum2=W(0,987673807,1036995374,-1095509641,-1094252408)+W(1,-1119095571,-1103179232,1040985329,-1114181285)+W(2,1027892228,-1102736131,1034852634,1059241808)+W(3,-1103859919,1043446486,-1109795439,1004807604)+W(4,-1103141235,1049007178,-1090760003,1060311666)+W(5,-1129798465,-1100012675,1051746582,-1113144024)+W(6,1005138532,1028221332,-1123669832,-1128511149)+W(7,1032914452,1006285508,-1122773902,987177167);WS(1058381774,-1086956646);
sum1=W(0,1005434106,-1149835360,1034370117,1036055789)+W(1,1007595428,-1173712576,-1122685332,-1119060568)+W(2,-1096145742,-1100460324,-1096424577,1033532617)+W(3,1049990129,1042033667,-1147483724,1021597150)+W(4,1046241393,1039571170,1054608457,-1110152984)+W(5,-1100950084,-1103984787,-1122634471,1016207588)+W(6,1026532260,-1120107684,-1107524072,-1123297125)+W(7,1032832748,1041584782,-1111048693,1023439817);sum2=W(0,1073050559,1069067455,-1096535796,-1073893027)+W(1,-1077684470,1038335059,994568047,-1109196141)+W(2,1049113865,1035642194,-1105600932,-1114871718)+W(3,-1104998692,1034875990,1004288083,1019116562)+W(4,1048373410,-1101089925,1050248373,-1113393188)+W(5,1015693919,1032989733,1024635942,1041247426)+W(6,-1123382260,1035361564,-1105239942,1000972215)+W(7,-1112223483,987872957,1016564448,1019016937);WS(1051792028,1027146209);
sum1=W(0,-1173418992,1031492470,1030866682,-1111745573)+W(1,1037975597,1032231158,1021051177,1029296729)+W(2,-1096555104,-1099279313,-1102472206,-1086728512)+W(3,-1098029143,-1099704976,-1107704157,-1088435526)+W(4,1048715847,1043543405,1045948678,1048944276)+W(5,1053562136,1041023999,1031959404,1046674105)+W(6,1037767898,1032372106,1031937048,1030986133)+W(7,1035090980,1038793940,1031982829,1043937550);sum2=W(0,1076285256,1067013205,1054912747,-1103468782)+W(1,-1082179927,-1086354611,-1086555076,-1077304359)+W(2,-1071495861,-1080654015,-1092768710,1053690657)+W(3,1062196550,1059230433,1065208788,1069826015)+W(4,-1089164092,1044446905,-1089831336,1049463752)+W(5,-1116071286,1055604285,-1102169042,1049830695)+W(6,1024798548,-1130255717,-1111620633,-1129289568)+W(7,1022374674,-1147177200,1008723412,990531682);WS(-1116843232,1041538044);
sum1=W(0,1038718416,1041393778,1023355030,1040958951)+W(1,1040537034,-1112360254,1043346413,1047211822)+W(2,1050813118,1048646402,1043671731,1037057641)+W(3,1050123337,1052799074,1037436293,1042212684)+W(4,-1091780513,-1107072481,-1097953353,-1088265503)+W(5,-1105750724,-1091053114,-1121572392,-1091261766)+W(6,-1107356403,1032833522,-1126022145,-1185162751)+W(7,1038008293,-1123581176,1033129910,-1116284746);sum2=W(0,-1127892588,1025248710,-1127740272,-1114879615)+W(1,-1125515678,-1135605467,1015277154,-1118452308)+W(2,-1090048491,-1124324076,-1092974499,1047668544)+W(3,1042122418,1052455522,-1102075660,1052515578)+W(4,-1076486023,-1080184847,-1080442855,1048567939)+W(5,1066323214,1068938556,1066205534,1058048535)+W(6,1071993665,1067215194,1068762214,1014309155)+W(7,-1079656754,-1077318729,-1083078137,-1086246531);WS(1045082936,1047750074);
sum1=W(0,1017867382,-1105827232,-1139557912,-1098507795)+W(1,-1112138258,-1113781499,-1117154624,1024003356)+W(2,1038967959,1036533543,1048524561,1057427781)+W(3,1057555836,1044700722,1037485187,1046059755)+W(4,-1107005280,-1101431328,1044741561,-1099209723)+W(5,-1103886606,-1117912777,-1108908881,1024367918)+W(6,-1117189504,1000061951,1034808454,-1102176472)+W(7,-1102736460,-1102956733,-1113728179,-1108156515);sum2=W(0,1003184961,971431442,-1131894760,-1133283297)+W(1,984723076,1031831407,-1125590160,1031681833)+W(2,1024857236,-1109323954,1026446282,-1105665514)+W(3,-1116186208,1024492508,-1121629964,-1148808497)+W(4,-1114215978,1030818718,1031262679,1056963612)+W(5,1055283667,975724297,-1116339968,1026784592)+W(6,1037587704,-1121823736,1045339410,-1107079097)+W(7,-1090072253,-1102678968,-1103014356,-1123463096);WS(1059869006,1015916977);
sum1=W(0,-1111801867,1039164638,1023424768,-1118862224)+W(1,-1114194639,-1099094340,-1118811114,-1096321008)+W(2,-1103727218,-1102716146,-1089648586,-1092420393)+W(3,1049092536,1052180160,1032231232,1046058153)+W(4,1051877295,1051739903,1057614174,1055627629)+W(5,-1096079006,1008315659,-1121275805,1039975892)+W(6,-1115491581,-1106752078,-1104830517,-1112797325)+W(7,1038662167,1030088557,-1131680577,-1175801754);sum2=W(0,-1113427160,-1104433368,-1104169884,-1117600576)+W(1,-1102319880,1039627671,-1097619580,1047721667)+W(2,-1090644207,-1091764889,-1109333336,1065407690)+W(3,-1098732665,-1109931470,1043714297,1041133481)+W(4,1034414883,-1120815960,995253792,1059846520)+W(5,1048874179,1008884504,1021072320,-1103318888)+W(6,1038986783,-1135559136,1033390214,-1120264784)+W(7,-1104270640,1019376128,-1111461786,-1142244432);WS(1054131356,-1077482588);
sum1=W(0,-1100136045,989703980,-1114161471,-1117800461)+W(1,1013262449,-1112319975,1027862775,-1103330903)+W(2,-1101215881,-1100083265,-1091699940,-1088812180)+W(3,-1095974704,1033042241,-1095224480,-1102789769)+W(4,1045307006,1039854844,1051542530,1056393300)+W(5,1053327664,1059113280,1049428707,1055440053)+W(6,1047064142,-1120855287,1042850313,-1122501592)+W(7,-1118254671,-1111473941,-1119385054,-1109190398);sum2=W(0,-1098032416,1055692800,-1101668743,-1100435053)+W(1,-1089098280,-1094416925,-1099202751,-1104551065)+W(2,1063396296,1024719031,1065491656,1073645059)+W(3,1060161647,-1074198531,-1081296593,-1083400329)+W(4,1043414797,1032661901,1058961916,1063424749)+W(5,-1096580753,-1098776178,-1115458644,-1092624053)+W(6,-1093635160,1049215120,-1090478816,1050905898)+W(7,-1135528507,1042380471,1032695397,1054277265);WS(-1082679118,-1072338335);
sum1=W(0,-1126832308,998650886,1029713605,1045660229)+W(1,-1125245511,1001090478,-1126242526,-1128346278)+W(2,-1092407662,-1099976035,-1098757312,1049242330)+W(3,1052609817,1049104969,958956607,-1170516592)+W(4,1041636256,1035459839,1053507448,-1097348797)+W(5,-1097111418,-1099322690,-1116731426,1009511091)+W(6,1032452512,-1118647007,-1113994637,1019901759)+W(7,1026546307,1041545965,-1113342195,1027607012);sum2=W(0,-1069228184,-1073602631,1021776922,1076866983)+W(1,1069809281,-1101499289,1013617559,1036050969)+W(2,-1099529380,1043301860,1054858487,1044685536)+W(3,1062109344,-1097491140,-1149319294,-1113127688)+W(4,-1112044089,1041147606,-1119872164,-1106846135)+W(5,1042271976,1035368326,1025827813,-1115137330)+W(6,-1144476451,-1112019052,1036271953,1018899191)+W(7,-1114284680,-1126672913,-1112053703,-1146921887);WS(-1125906880,1029353026);
sum1=W(0,1052620124,1040928385,1053619569,1034478636)+W(1,-1149501032,1027228408,1033816441,-1143379631)+W(2,-1082830235,-1087911853,-1088553290,-1115166792)+W(3,-1104403058,1046902211,-1140598044,-1115398454)+W(4,1044570800,1048894344,1054767249,1052323270)+W(5,-1096342700,-1092690897,-1112660402,-1089842615)+W(6,1033131793,1031982257,-1118254573,1037418321)+W(7,1045103465,1053685367,1032758420,1056771243);sum2=W(0,1052242091,-1105901664,1041713460,-1098081544)+W(1,-1101414896,-1140318759,-1123485994,-1108472633)+W(2,-1123374674,1032004261,1057464262,1055897675)+W(3,-1108453649,-1099401944,1039811869,-1092934450)+W(4,-1088438592,-1109896025,-1106721416,1057898227)+W(5,1044097375,1041656473,1042751001,1033994653)+W(6,-1109756837,-1117902306,-1106560728,-1101499608)+W(7,-1114554169,1042131382,-1104786072,1048148308);WS(-1080878567,1068324028);
sum1=W(0,-1115471279,1019310859,-1121098697,-1115193805)+W(1,-1153442440,-1104713039,1023975060,-1094675607)+W(2,-1095139206,-1103458412,-1090917913,-1094785898)+W(3,-1100131090,-1118370765,-1102569730,1044057356)+W(4,1057833304,1049561152,1058273109,1054221326)+W(5,1050583410,1048985266,1041261354,1045920684)+W(6,1032811018,-1118469827,-1107876783,-1109399058)+W(7,-1121957752,-1109945243,-1125987028,-1144681671);sum2=W(0,-1122597644,1032420914,-1109997244,1029919127)+W(1,-1129031901,1025876905,-1121404056,1025649559)+W(2,1052263517,-1132353885,-1113437764,-1086124512)+W(3,-1134522929,-1137529969,1041285329,-1111439550)+W(4,1084267296,1077171750,-1076080701,-1066836895)+W(5,-1073829589,-1128728545,-1128683125,-1109934248)+W(6,1037076324,1017945885,1045994672,-1105598049)+W(7,-1115453382,1027437378,-1112127416,1032857588);WS(-1106960696,-1099012034);
sum1=W(0,-1114528403,-1119077260,-1143558020,-1119877760)+W(1,-1109244232,-1096650748,-1112604445,-1100402892)+W(2,-1099071342,-1099370430,-1089278443,-1086538844)+W(3,1010994112,1041376829,1042854492,1049345155)+W(4,1055554285,1049964157,1061104081,1056629915)+W(5,1049997315,1042073805,1031563405,-1123516568)+W(6,-1109121109,-1115766890,-1114965299,-1120868875)+W(7,1034547527,-1114495407,-1139584324,-1118254096);sum2=W(0,-1116593925,1028908115,999050165,1037914955)+W(1,-1106109711,-1105957739,-1123834115,-1113783754)+W(2,1027806287,-1136470458,1039840949,-1122048333)+W(3,1057135276,-1105275062,-1096566133,-1105721601)+W(4,1032648371,1006654490,1052059722,1057985079)+W(5,-1090440242,-1131926605,1018741845,-1124260101)+W(6,1024756439,-1116529299,-1107372324,-1128153177)+W(7,-1142966917,-1123338691,1013415162,1018182189);WS(-1103089976,1059868827);
sum1=W(0,1026631887,1033737723,1034000797,-1130496915)+W(1,-1106694966,-1105866475,-1106727101,-1098705919)+W(2,-1091300264,-1096562704,-1087537316,-1094386976)+W(3,1044429902,1045093007,1040636078,1044615672)+W(4,1056895190,1050565142,1059766350,1053939124)+W(5,-1108577640,-1109922270,-1122075862,-1100982776)+W(6,1031003956,-1140469197,-1108911023,1032926090)+W(7,-1120892680,1034482579,-1136817768,1045052014);sum2=W(0,-1114832682,1038307608,-1109268272,1031259614)+W(1,-1136199018,-1118450441,1025376385,-1125957173)+W(2,1044376552,-1101986459,1025272345,-1112738770)+W(3,1014008179,1042085570,-1110075404,1027010884)+W(4,1052671036,-1094811671,-1106762472,1052706603)+W(5,1040752903,-1100877636,1051973899,1036345951)+W(6,-1084839384,-1076225566,-1074779618,-1088390497)+W(7,1066038403,1071357616,1068318141,1050587817);WS(-1089897038,998399462);
sum1=W(0,-1100326508,-1099771006,-1103969415,1030998252)+W(1,-1111096702,-1129527451,-1115021151,-1124899748)+W(2,-1114312802,-1109889234,-1092992143,-1098209637)+W(3,-1116385180,-1096464604,-1111889198,-1109224641)+W(4,1049930251,1047140918,1060325312,1062808044)+W(5,-1128865717,1048691588,-1137813989,1043572929)+W(6,-1141222070,-1114407115,-1106384368,1017922927)+W(7,1023432554,-1125954964,-1121716413,1020452535);sum2=W(0,-1094975511,-1089233591,-1089977002,1033778332)+W(1,1006981461,-1137053176,-1125132764,979684320)+W(2,-1113696880,1032844980,1066397244,1037917830)+W(3,1039504138,1032622380,1021506052,-1119563165)+W(4,1023473326,1036803698,-1129026618,-1104280508)+W(5,1024702770,-1121975322,974010432,-1138205260)+W(6,1029862812,-1117299445,1025970568,1031377784)+W(7,-1122944997,1022461928,-1130740686,1024270227);WS(-1096120220,-1099720911);
sum1=W(0,1052677544,1027883172,1046184634,1036941212)+W(1,1037786724,1039372749,992842790,1040590154)+W(2,-1105594052,1050583742,1030711656,1050761182)+W(3,1044997418,1051859318,1041579690,1052858474)+W(4,-1101878153,-1120505890,-1094174707,-1087347673)+W(5,-1091299260,-1092171165,-1105854769,-1087724293)+W(6,990296621,1026529890,1039246623,1031039363)+W(7,1038193547,1036921611,-1115076484,1007468831);sum2=W(0,1040381409,-1131846701,1030695069,1015259161)+W(1,1026868853,-1164136976,-1121164685,-1109936403)+W(2,1023777345,-1095435966,-1111411494,-1085163747)+W(3,-1100600319,1052695808,1041440525,1051545155)+W(4,-1110031849,-1146822820,-1089001391,-1074171332)+W(5,-1078760233,1048168469,1074132102,1072577306)+W(6,1022623295,-1096899181,1049343346,-1107180310)+W(7,1043071461,1020495459,1017314953,1050115198);WS(-1080112807,-1111145054);
sum1=W(0,-1103297132,-1106341774,-1098278655,1024154699)+W(1,1037514093,1034961350,-1125780682,-1109009483)+W(2,1049824404,1049617192,1059552348,1031972225)+W(3,-1085661228,-1097823136,-1114326813,-1119831648)+W(4,-1133975251,-1122989109,-1086286580,-1137351813)+W(5,1056970252,992708574,1021582000,1040424089)+W(6,1026400021,1042898005,1041608840,-1145221295)+W(7,-1102084285,1041904442,1038246926,1042525799);sum2=W(0,1041258750,-1109734283,-1123542769,-1113561957)+W(1,-1110564237,1026811493,-1130694514,1024057869)+W(2,989910477,-1100922013,-1096844113,1051742866)+W(3,-1100235579,-1105813951,-1151284621,-1136706867)+W(4,-1134607603,1016064722,1041392492,1057819912)+W(5,1047439582,-1113868277,-1118083589,-1114600003)+W(6,-1109794979,1041809078,-1126381362,982123162)+W(7,-1119465765,1026735929,1019553626,-1114678252);WS(1043409720,-1105036943);
sum1=W(0,1040191749,1033970558,1042494496,1046767380)+W(1,972615552,1032778168,1032217109,1032356247)+W(2,-1096303173,-1095924673,-1093807736,-1092831585)+W(3,-1096756208,-1126846855,-1115229280,-1098580285)+W(4,-1115184605,1041748910,1044442592,1042876074)+W(5,-1140612185,1018241414,1027878365,1034858676)+W(6,1041655059,1041917006,-1160531625,1039311757)+W(7,1020654492,1043700571,1034107952,1036396440);sum2=W(0,1027808259,1010119787,-1111510504,-1113418759)+W(1,1032132185,-1121052855,1014515195,1010692603)+W(2,-1139047739,1043340308,-1106790738,-1096910874)+W(3,1040059331,-1115460243,1017581734,-1120741339)+W(4,986751832,1026247831,1065364148,1040723354)+W(5,1038861011,-1113647147,1041604470,-1135975307)+W(6,-1095774205,-1093511024,-1089533357,1053173071)+W(7,-1106558855,1027584935,-1121443175,1014681515);WS(1035857520,1029952289);
sum1=W(0,-1143077795,-1105351783,-1113811952,-1106526780)+W(1,1035289215,999420801,-1129002434,-1113970285)+W(2,1037051011,1029971495,1049064844,1035603988)+W(3,-1083894414,-1098557596,-1111645039,-1130790920)+W(4,-1110400621,-1106469910,-1094483622,1058276716)+W(5,1056346487,1050633420,1042325343,1026109447)+W(6,-1121149466,1043652126,1027875988,1035104701)+W(7,-1114346217,-1123554317,-1130799743,1025377311);sum2=W(0,-1118517607,-1101077931,1029148161,-1087996420)+W(1,1047526016,-1108756119,1038718292,1024464693)+W(2,1026484093,1046485772,-1098019518,1071267691)+W(3,-1082674625,1032470282,-1106613565,-1113199029)+W(4,1039465846,1030900361,1048118782,1064954318)+W(5,-1084489705,-1118487613,-1112021711,-1120012731)+W(6,1008581907,-1114630284,-1106945018,-1097625455)+W(7,-1156379726,1024110641,1020048570,1036291722);WS(1058189134,1034857672);
sum1=W(0,-1171748679,-1105475825,-1097172873,-1108837708)+W(1,1038034707,-1131134898,-1113151849,-1119273967)+W(2,1031241360,1044072484,1057114388,1051374554)+W(3,-1083662360,-1099379283,-1121036423,1018101850)+W(4,-1100969760,-1094075536,-1082247827,1060030327)+W(5,1058651386,1046921459,1041721673,1036514264)+W(6,987174985,1045893176,1042860595,1031954257)+W(7,-1120638978,-1137288661,1037681908,1029972391);sum2=W(0,1003810984,1036204547,-1101998989,1041029203)+W(1,-1098215637,1044393168,-1110527635,1027560485)+W(2,1020569783,-1114489126,-1121260135,1052640914)+W(3,1059150102,-1098121773,1037147118,-1110248773)+W(4,-1128982694,-1099380876,-1101918458,1059611184)+W(5,1040381797,-1094102036,1028175839,-1113935142)+W(6,1043745048,-1104004872,-1104165612,-1121067579)+W(7,-1100369008,1032515174,-1114899975,1000033398);WS(-1107450480,1040804833);
sum1=W(0,1040192716,1022226221,1002013395,-1117682794)+W(1,1001040843,1000424795,-1120982404,1025306833)+W(2,1040473489,1047969017,1044185574,1060667554)+W(3,1057909434,1049088596,1038016429,1042416864)+W(4,-1095196747,-1098407451,-1087290490,-1089168888)+W(5,-1111951852,-1119291421,1031577591,-1112956481)+W(6,-1124855402,1020416041,-1160070647,1045737613)+W(7,-1101676720,-1103624738,-1104451167,-1115902938);sum2=W(0,1014727333,-1117243126,1029406572,1027900147)+W(1,-1112527674,-1114664521,-1111634336,-1107116047)+W(2,-1124633329,-1107065949,1041729284,-1094200388)+W(3,-1104959017,1040214496,1005029260,1049039902)+W(4,1026257754,-1111801245,-1084100906,1052541581)+W(5,1070744988,-1111707080,-1127513012,-1107038609)+W(6,-1111611661,-1136702760,-1103677442,1050798725)+W(7,-1105828213,-1111536822,-1106506739,-1140667375);WS(-1113867888,1064515135);
sum1=W(0,-1113562537,-1107046062,-1103978495,-1098739202)+W(1,-1122423580,1019693149,-1116789880,1020558520)+W(2,1048061265,1043460993,1060048584,1062873548)+W(3,-1119786749,1023528257,-1106657727,-1137576074)+W(4,1011269086,-1098944190,-1107431310,1045822761)+W(5,1025265092,-1112998912,-1142662356,-1104660585)+W(6,-1105945126,-1148623547,-1111558073,-1114838028)+W(7,-1101841139,-1117915947,-1106868487,-1122252061);sum2=W(0,-1145158406,1012385731,1016118130,1024197601)+W(1,-1112179804,-1119519161,-1127326042,-1113792718)+W(2,1022878354,-1129472106,1044961455,1049544336)+W(3,1030346877,-1131221354,-1095482557,-1093377057)+W(4,-1111624996,1015658802,1040055751,1057430996)+W(5,-1114498280,1020564842,-1112131584,1019749938)+W(6,1010204019,-1123973089,-1157676569,1022031298)+W(7,-1124728962,1023003938,-1121117277,-1141925830);WS(1051333020,-1087054195);
sum1=W(0,-1112042433,1019002067,-1115058903,1046618143)+W(1,-1107874438,-1148774132,1036768028,-1154881470)+W(2,-1104387605,-1096771599,-1102529947,-1093976551)+W(3,-1089735051,-1129150690,-1101876091,-1098135714)+W(4,1052246829,1048899277,1054136106,1044227957)+W(5,1060328029,1046377228,1045160291,1045432325)+W(6,-1113527444,-1098301717,-1095193948,1044013586)+W(7,-1107288943,1038700845,1024370318,1019966234);sum2=W(0,-1114066012,1029900262,-1114806697,-1110038644)+W(1,1036646832,-1110070018,1020625547,987867800)+W(2,1041392892,-1112610934,1041587346,1025557898)+W(3,1055783298,-1102485451,988088600,1039502616)+W(4,1044719218,1046575198,1050162797,1055420600)+W(5,-1099287148,-1100701871,1033323822,-1119304428)+W(6,-1097547793,-1095644935,-1102972970,-1095936036)+W(7,1028020818,-1113902766,-1135974783,1018696751);WS(-1120103648,-1090070191);
sum1=W(0,-1117418940,1024592611,1040968250,1049918615)+W(1,1034410595,1035134604,-1119948353,-1144523437)+W(2,1049030490,1050801054,-1111205267,-1116228463)+W(3,1050512309,-1102511675,1034763283,1039656998)+W(4,-1112262737,-1094705236,1042055990,-1085341341)+W(5,-1106227665,1036298997,-1138448657,-1110564136)+W(6,-1114427969,1032013281,-1110419822,1047944497)+W(7,-1132367051,1025392341,-1111046724,-1120201127);sum2=W(0,-1122606938,-1141997982,1027805544,-1120462650)+W(1,-1100560083,-1105726471,1025575588,-1113668318)+W(2,1046354401,1040228902,-1143835982,1061896257)+W(3,-1080731069,-1098049024,1026943708,1032253740)+W(4,-1124762815,-1102583710,1052785838,1059397472)+W(5,-1120768779,-1126645315,1011421951,-1122685018)+W(6,-1118515993,1036845124,-1106443071,1043676745)+W(7,995709275,-1128858827,-1112152255,-1127110207);WS(1060158670,1068766623);
sum1=W(0,-1116432453,-1131098839,-1099753724,1034945056)+W(1,-1122123599,1040823512,1040184285,1050332416)+W(2,1056712636,1049784895,1057908127,1044163070)+W(3,1028198895,-1122504371,-1123329903,-1096645803)+W(4,-1087151539,-1102593034,-1089291740,-1094800699)+W(5,1036808107,-1120242995,-1127465369,-1132187055)+W(6,1040295867,1033948341,1031077093,1027113355)+W(7,-1132674679,-1117547229,1040274980,-1137741501);sum2=W(0,1036379663,-1108907739,1070189048,1073213180)+W(1,1065321765,-1076673488,-1079893128,-1072585926)+W(2,-1098232449,1058983203,1016986873,1047923452)+W(3,1033582270,1031365639,1038048757,-1107019906)+W(4,-1128107780,1035811659,1040144345,-1105399966)+W(5,-1110681209,1039880527,-1116001167,1018297481)+W(6,-1120677803,-1120240179,1029686139,-1109097268)+W(7,1041308319,-1109042515,1034493417,-1131123922);WS(-1112459888,1031046963);
sum1=W(0,-1112719265,-1129483154,-1103727283,-1091575740)+W(1,-1104335643,-1155155940,-1114094348,-1105426861)+W(2,-1128634346,-1120462421,-1112785958,1056781779)+W(3,-1153409228,-1108013960,-1118230989,1027667442)+W(4,1043326546,-1103778738,1050524372,1067939282)+W(5,1048587330,-1132710977,-1109505653,1036777787)+W(6,-1115081924,-1114915140,-1104237825,-1096588493)+W(7,-1108534894,-1114726045,991235804,-1111746006);sum2=W(0,-1119086167,1013020612,-1141008560,-1108719150)+W(1,1023891147,-1145112744,1018251990,-1116478859)+W(2,1037241732,-1129818230,1029187991,-1074141953)+W(3,1019083994,-1124211508,-1122886966,1027168441)+W(4,-1114652243,1028260797,-1112264831,1072760747)+W(5,1042535682,-1131878972,1037493286,-1129254230)+W(6,-1131518324,-1115730540,1036245214,1034705438)+W(7,-1119172530,-1133917220,-1114007324,1018465006);WS(-1086783566,-1086791567);
sum1=W(0,-1115195632,-1153026662,-1134496297,-1108787789)+W(1,-1119803561,-1145121243,-1131708777,-1110064394)+W(2,-1095708330,-1093442522,-1098161001,1044632085)+W(3,-1091375169,-1107384199,-1100078210,-1104664012)+W(4,-1123676804,1018199561,1037878573,1064261167)+W(5,1057417647,1052226946,1046948682,1047330733)+W(6,1041725033,-1121101892,1034570216,-1103584185)+W(7,-1108866704,-1122033784,-1117964907,1022321300);sum2=W(0,1031515378,-1121810184,1010081392,-1119765868)+W(1,1035546479,-1106495935,1028378344,1003402623)+W(2,-1077397139,-1079753374,1044674665,1073378801)+W(3,1056367001,-1109376902,1035615024,-1118889676)+W(4,-1134939312,-1097085111,1052841311,1007836336)+W(5,1044809025,-1118570548,992033726,1010750288)+W(6,-1112896962,1035985281,-1105060263,1031953140)+W(7,1022446080,1031289566,1032016077,-1150317246);WS(-1096711324,-1080143969);
sum1=W(0,-1135181951,1025399430,1033906501,1041786535)+W(1,-1133559462,1003671004,-1123695637,-1105366874)+W(2,-1095339398,-1094144146,-1093853897,-1089314149)+W(3,-1089126233,-1110956839,-1129083412,-1113909272)+W(4,1050582337,1049483953,1045129706,1046728732)+W(5,1045641984,1051092970,1049638101,1057307443)+W(6,1026786373,-1123204644,1006467326,1031608549)+W(7,-1135165794,1017185520,996324016,1009923752);sum2=W(0,1023911567,1004932796,-1119124867,1022775023)+W(1,1011639102,1036397588,999444348,-1106309084)+W(2,-1108118447,-1134375038,1035251904,1037995724)+W(3,1050162042,1037707684,-1111062570,-1101285996)+W(4,1044892126,-1138359022,1063133445,1074655410)+W(5,1070062472,-1083132698,-1073510095,-1073687480)+W(6,-1112738860,1020475455,-1102926770,1047698054)+W(7,-1113839430,-1117927031,1017195567,1041743674);WS(-1089880270,1068594400);
sum1=W(0,-1114467040,1023170830,1036273894,-1107800974)+W(1,1029867434,-1106779367,1024593089,-1110449433)+W(2,-1104513741,-1091458130,1034367029,-1100997781)+W(3,-1095286649,1047811540,-1096228817,-1109179032)+W(4,1050219169,1042545281,1048674674,1042739212)+W(5,1053624831,1034908007,1034674708,1049808694)+W(6,-1118490053,-1120682309,1031296832,-1110241363)+W(7,1034289100,-1107012174,1021221591,-1126204757);sum2=W(0,1030004067,-1117028113,-1105887481,-1066126465)+W(1,-1104777348,-1122550707,-1130918117,1023720579)+W(2,-1133064657,-1134091777,1045929484,1081917443)+W(3,1043726141,1028310407,1016764395,-1116064873)+W(4,1024174065,-1113615539,1032698350,-1097201480)+W(5,1033613382,-1107697461,1029778305,1018371831)+W(6,-1119836251,1025775761,-1118489229,1041573100)+W(7,-1124268877,1030764051,-1116797441,1018350967);WS(1067475431,-1126058166);
sum1=W(0,-1108052732,1043040440,1048922396,-1097574342)+W(1,-1119673025,-1101774749,1019400344,1007801026)+W(2,-1097851361,-1108210069,-1084429932,1055911149)+W(3,1041902328,1035827603,-1115594513,-1107003538)+W(4,1049362324,1048929252,1054104112,1047147106)+W(5,-1085779789,1049622021,1019477630,1037086373)+W(6,1040199303,-1109622414,1041203782,-1104274751)+W(7,1047880876,-1116198608,-1107876353,1036701569);sum2=W(0,1013753738,-1113150555,1015248850,1042650722)+W(1,1040818978,-1105652199,1033430289,-1120377801)+W(2,1020731454,1046742995,1045156685,-1104352239)+W(3,-1089864705,1045331461,-1109224259,1016214593)+W(4,-1120697178,1034035253,-1094710566,-1128318417)+W(5,1045040370,1025091411,-1106535436,1019751894)+W(6,1009873360,-1099358283,1039470065,1046693145)+W(7,1036008061,1030627793,1017876415,-1132110931);WS(1060496974,-1099362699);
sum1=W(0,1054706808,1036662868,1045895019,1033303646)+W(1,1044095763,-1130190200,1035564779,1040746168)+W(2,-1109706041,1041317773,1051554925,1049334366)+W(3,1051166813,1053590462,1049285205,1055551482)+W(4,-1098091909,-1123237413,-1091928498,-1083798889)+W(5,-1095315343,-1087007295,-1097088265,-1094550458)+W(6,-1129324363,1015757258,1021341985,-1112852963)+W(7,1041804248,-1127492145,1039262630,-1114905285);sum2=W(0,-1073385920,-1084887580,-1083140914,-1081800202)+W(1,-1085954594,1037413129,-1096433065,1054210787)+W(2,1077926840,1058818874,1060159151,1074845707)+W(3,1061906872,-1084431515,-1126824848,-1087315344)+W(4,1032559783,-1089669880,1045764296,1059775011)+W(5,-1103860568,-1094536545,-1133232881,-1099186518)+W(6,-1094451238,-1121878040,-1173171215,-1120435570)+W(7,-1115590029,1053315192,-1107838893,1052978812);WS(-1078369703,1041267413);
sum1=W(0,1024386586,-1098405416,1044040033,-1098286219)+W(1,-1130684104,1045750173,-1098338270,1041584973)+W(2,1041630887,-1112635974,-1132435208,1041292515)+W(3,-1091497929,1016159377,-1139597330,-1101611546)+W(4,-1102607056,1051293608,-1094040968,1052507157)+W(5,1056853585,-1105775474,1049412460,1026100205)+W(6,1016693023,1018393854,1046099151,-1095618428)+W(7,1018959206,-1117949682,-1118540325,1040982949);sum2=W(0,1035615459,1028814353,1062855981,1052250964)+W(1,1056109526,-1106019250,1048995011,-1115640692)+W(2,-1097925659,1038714809,-1077657685,-1101970047)+W(3,-1098468896,-1114182260,-1104046747,-1130122971)+W(4,1043665288,1033337220,1051048913,-1113114333)+W(5,-1085664062,1040975429,-1109605260,1034778788)+W(6,1020457849,-1103657321,-1109823715,1058024935)+W(7,1056999181,-1105846491,1042595027,-1112374505);WS(1049151900,-1114127847);
sum1=W(0,1050216581,1000015204,-1136218178,1023136961)+W(1,-1130455775,-1133465094,-1160090192,1035991733)+W(2,1044969414,1047621718,1057314961,1055877843)+W(3,1054358666,1052966059,1045850836,1052491071)+W(4,-1106856243,-1112471205,-1091938023,-1092033343)+W(5,-1099719178,-1089783713,-1099053307,-1087984664)+W(6,-1099359923,-1148711507,-1133921207,-1112054390)+W(7,1034273823,-1122838974,1019980258,-1112322824);sum2=W(0,-1105478410,1039552519,-1131405058,-1099466970)+W(1,1049027924,-1115050596,-1129231446,1049583286)+W(2,1011113448,1050864081,-1125310098,1043215106)+W(3,1034334973,-1095883745,1036178144,-1088635155)+W(4,1068049752,-1103020148,1066695202,1074596924)+W(5,1067601936,-1084539788,-1075514015,-1074115054)+W(6,-1082501551,1059003564,-1098156272,1039344435)+W(7,-1099880092,-1107282542,-1097076855,1042018058);WS(-1081332839,-1093454830);
sum1=W(0,-1109709318,-1104916884,-1108177419,-1117212646)+W(1,-1119705461,1032417267,-1118748528,987327371)+W(2,1035356975,1037116623,-1125155242,1030327966)+W(3,1050241163,-1103907222,1046095669,1033262333)+W(4,1039420520,-1122158672,1053028347,-1104761999)+W(5,1032136206,-1115200780,-1115609017,1029855614)+W(6,-1111308088,1014687039,-1112931654,1020526050)+W(7,-1119448076,-1112611266,-1136487898,-1104533373);sum2=W(0,1013207527,-1127355075,-1103159789,1040955478)+W(1,1008876024,-1116686760,1035764738,-1154118338)+W(2,-1118344664,1028266047,1043690369,1051132935)+W(3,-1108842627,1041402295,-1105537330,-1128237045)+W(4,-1124997045,-1117884424,-1116887196,1047094008)+W(5,1057384051,-1100609336,-1098518151,-1089828796)+W(6,1036829905,1016171285,1024917624,1041601336)+W(7,-1127506713,1033786361,-1114313206,-1102385561);WS(1063446990,1030048893);
sum1=W(0,-1131562670,-1099483503,-1106193120,-1102405700)+W(1,1021119810,-1113568905,1009340592,1030255032)+W(2,1043069042,1049571969,1061428532,1053095529)+W(3,-1115069793,-1119868742,1027160065,1043118346)+W(4,-1108681470,-1106599551,-1097709592,1046689338)+W(5,1029025472,1006738196,-1120287391,-1111789333)+W(6,-1108650254,-1106453175,1008661917,-1102088711)+W(7,-1123233168,-1104754348,-1136963210,-1114502129);sum2=W(0,1012371361,-1149491589,1023756477,-1165255819)+W(1,-1111467932,1019335917,-1140694601,1010513313)+W(2,1017109065,-1115161102,1012418345,-1111308586)+W(3,1015942947,-1106016138,1015823021,1026481588)+W(4,-1110016822,-1109821790,1060485172,1031379047)+W(5,1046805034,-1114576028,1024897044,-1114618076)+W(6,-1103671135,-1097972516,-1094449842,1049769129)+W(7,999148403,1022790203,1032463998,-1146831635);WS(1060385486,1040268319);
sum1=W(0,-1115333181,-1113839600,1026945989,1041834949)+W(1,-1100015113,1010458454,-1113704543,-1110169699)+W(2,-1105770459,-1104706211,-1085502934,-1112644646)+W(3,-1102865873,-1112283012,-1108020290,-1115522389)+W(4,1048230464,-1122113023,1051932092,1065603891)+W(5,-1105250533,1054415097,-1122402466,1046973419)+W(6,1022495614,-1115044751,997701279,1044329112)+W(7,1038196649,-1113673817,-1105082025,-1115640050);sum2=W(0,-1115664423,-1122287706,1044568139,-1099350461)+W(1,-1102715015,1042022920,1031291077,1032474264)+W(2,1041813775,1041645390,-1087138046,1067461852)+W(3,-1116572542,-1109622665,-1113357449,-1110133469)+W(4,-1142717933,-1094011677,-1124627987,1027339570)+W(5,1045144111,1054026149,-1122353792,1047364150)+W(6,-1120925434,-1119842210,-1120985148,-1113918825)+W(7,-1100833175,-1101147879,-1112018489,-1109170005);WS(1049043868,1050086952);
sum1=W(0,-1127858130,1025810768,1034666762,989092984)+W(1,-1115481017,-1119959429,1012364567,-1097661520)+W(2,-1091279607,-1101354119,-1089232423,-1092016019)+W(3,-1089729669,-1104525366,-1121438163,-1160888088)+W(4,1054362490,1044465651,1050465752,1058690160)+W(5,1053482909,1051092259,1019953121,1051219071)+W(6,1028884238,1022883995,1032068165,1005443958)+W(7,1007092039,-1149438996,-1137072337,1017307814);sum2=W(0,1030282550,1012065197,1049708534,-1101566471)+W(1,1043525707,1038111746,1040589253,-1106531005)+W(2,-1099759289,1050936278,1018991152,1050588571)+W(3,-1112383125,-1121285468,1039884984,-1113841779)+W(4,1070065566,1068820850,1068572253,1075164582)+W(5,1046261639,1053555382,1040055978,1058828770)+W(6,-1078832473,-1076346523,-1075628240,-1072955990)+W(7,-1093459475,-1088795804,-1099780818,-1090423367);WS(-1083655502,1074535575);
sum1=W(0,973651072,1028862937,1029517469,-1111330742)+W(1,1043404639,-1105397947,-1129726574,-1099887737)+W(2,-1100106921,-1096173461,-1088250868,-1101351113)+W(3,-1092528244,1034877328,-1113904430,-1118418050)+W(4,1049212555,1052529147,1057957824,1060855844)+W(5,1050267538,-1104065896,1041335934,1047916353)+W(6,-1122472503,996549482,-1111380529,-1125410415)+W(7,-1109626381,-1122247818,-1108333759,1037233742);sum2=W(0,1037582341,1032149251,-1135487115,-1107247151)+W(1,1053968825,-1096732175,1034930229,-1094249638)+W(2,-1116649305,-1112916551,1044443302,-1117703407)+W(3,1049963138,1042101117,1046616621,-1127010106)+W(4,-1107051108,1041643977,1030763641,1053360182)+W(5,-1087331905,-1089009482,-1110671517,1059951262)+W(6,1040538112,-1112067691,1036263743,-1115814520)+W(7,1035849297,-1104153316,-1104877620,-1116847106);WS(-1132786560,1056578758);
sum1=W(0,1031072232,1019453021,-1112153353,-1127115205)+W(1,-1153314582,-1105591705,986346381,1024604121)+W(2,1043718831,1050053971,1057505465,1049535379)+W(3,1052394474,1045418390,1044283028,1048806335)+W(4,-1098888378,-1104586611,-1090760605,-1081773448)+W(5,-1106021324,-1120283669,1036365944,-1103287167)+W(6,-1123786893,1030360908,-1123598824,1035671447)+W(7,1044649456,-1105554848,1033186457,-1108912601);sum2=W(0,1040658557,-1106354313,1027144364,-1103628435)+W(1,-1123462592,-1130705048,-1126068784,1016031184)+W(2,1011638864,1020064744,1049840877,1050147177)+W(3,-1117174472,-1105120318,-1113970774,-1135769248)+W(4,1041865287,-1103147627,1026998340,1053587315)+W(5,-1118058864,1036775410,-1104140895,1030416564)+W(6,-1109113498,1033931950,-1120927100,-1102211113)+W(7,1033328738,-1101351534,1028877580,-1112076066);WS(1062711758,-1109562142);
sum1=W(0,-1107075140,-1125545776,-1121788380,-1112684886)+W(1,-1128625782,-1102890883,-1129119788,-1102110160)+W(2,-1100622401,-1104747337,-1103229831,-1083301774)+W(3,1050510715,-1097610180,-1109077454,1030737729)+W(4,1053288051,1049612355,1059638178,1048337697)+W(5,1052952654,1051307580,1041285742,1049115768)+W(6,1017596397,1007433175,-1120034657,-1098025711)+W(7,-1112854653,-1108240645,1022176121,1020667959);sum2=W(0,1022257834,1033804876,1033963400,-1113268759)+W(1,-1123922685,1029999681,1015463858,-1125618402)+W(2,977550902,-1105772859,-1098748483,1063293804)+W(3,-1090033704,1051039483,-1104977553,1022914778)+W(4,-1113927342,1042844173,-1096777339,1059312088)+W(5,-1134320563,1037687330,1024487701,1004875175)+W(6,1036504102,-1107093105,1028160469,-1089861840)+W(7,-1101525036,1017532722,-1122996995,-1116068477);WS(1046002488,-1083997249);
sum1=W(0,-1116203964,1044431961,1041235242,1046371486)+W(1,-1106267745,-1117705943,-1122870401,-1109240562)+W(2,-1099156844,1028498222,-1096363997,-1079124621)+W(3,-1088685662,-1103556299,999993136,-1106798659)+W(4,1050076828,1049400252,1050263757,1020370202)+W(5,1048790666,1053355933,1034829570,1037276039)+W(6,1025075217,1035032656,1032516798,1050189128)+W(7,1042510329,1039724554,1027729159,1037249299);sum2=W(0,-1094982381,1024745423,-1097113645,1017043870)+W(1,1052555320,-1107563793,1049262968,-1118735987)+W(2,1041875660,-1091311273,1042706326,-1148119319)+W(3,-1098101314,1010824956,-1094774489,1030619863)+W(4,1017839086,1044409386,974632891,1061393923)+W(5,1043955676,-1098402228,1042935118,-1094515595)+W(6,1045890174,-1107764806,1048260200,-1118443235)+W(7,-1097368628,1041238578,-1116185663,1042214090);WS(-1083255246,-1075588436);
sum1=W(0,-1154522904,-1106371438,-1105464695,1036086422)+W(1,1023783355,-1127243930,1030176790,1031412139)+W(2,1026375684,1036249778,1056687627,-1097055709)+W(3,-1088556578,-1108055408,-1105944807,-1123388097)+W(4,-1099839750,-1113752075,-1092436626,1050924256)+W(5,1056650964,1045926824,1039385437,1041066449)+W(6,1037990411,-1119606102,1043935324,1036476796)+W(7,-1111337285,-1110940389,-1124332025,1021333175);sum2=W(0,-1117330831,1023708058,-1133288218,-1122435213)+W(1,-1139180683,1020252429,1025188082,-1109968059)+W(2,1032531181,-1114369361,1017487862,1047518334)+W(3,-1122916014,1027012545,-1103557501,1046855474)+W(4,1043756688,1031926890,-1104593512,1043258354)+W(5,-1096895795,1049767697,1019544307,-1112657711)+W(6,1060766869,1067300065,-1105945514,-1075696003)+W(7,-1102393264,-1106946489,1020047431,-1113285900);WS(1056055196,1023945849);
sum1=W(0,-1104545849,-1139517988,-1101013315,-1136100212)+W(1,-1148373856,1013350648,-1120654743,-1108930702)+W(2,1036175954,-1138851412,1048468083,-1097789539)+W(3,-1096999890,-1097071058,995622088,-1128233700)+W(4,1032040419,1009002268,1040659763,1059870683)+W(5,1039368714,1053644410,-1122818538,1033002810)+W(6,-1111539988,1026875367,-1104005681,-1112873620)+W(7,-1135793772,-1132670698,1028030253,-1133516850);sum2=W(0,1033182461,-1135790885,1036058972,-1145806187)+W(1,1026470367,-1125994579,-1123856921,-1152817846)+W(2,-1110992702,1041801313,-1115959119,-1083556559)+W(3,1047402951,1026458945,1021989349,1029289545)+W(4,1011638125,976542168,-1106760241,-1068720208)+W(5,1080067579,1043021822,-1118809257,1027196491)+W(6,-1116812221,-1135785781,1013579453,1034110873)+W(7,1048786168,-1124564059,-1115658442,-1110636256);WS(1047050040,1036867972);
sum1=W(0,1031952202,1040033213,1049413776,1052329098)+W(1,-1134253939,1023712847,-1129317744,1023414180)+W(2,1041031945,1050476745,1016870010,1054273441)+W(3,1041748879,1035493153,1041656495,1041394937)+W(4,-1098508279,-1097704487,-1091275871,-1087382286)+W(5,-1095309386,-1117526273,-1112254893,-1108492595)+W(6,-1117663192,1033331580,1012948685,1043041286)+W(7,-1131302504,-1125396951,-1153578470,-1112644847);sum2=W(0,-1120609508,-1098653081,-1074671298,-1081276780)+W(1,-1097107702,-1110118090,-1137118351,-1119823807)+W(2,-1138324119,1042859622,1072071026,1068070176)+W(3,1044485226,1040658983,-1118978815,1035453187)+W(4,-1110367912,1038385587,1026263792,-1107049493)+W(5,1024907208,-1122488627,1038809437,-1111098449)+W(6,1021280635,1026624912,1026288466,-1122098825)+W(7,1040255596,-1152233050,-1126727249,1006813455);WS(1047287096,1059538103);
sum1=W(0,1030804480,-1111595219,-1123153834,-1098057279)+W(1,1007980582,1018775223,1036089754,1030691489)+W(2,1034749929,1051408038,1049213285,1057344539)+W(3,1048793645,-1106759404,-1115115061,1033654600)+W(4,-1102474905,-1094490621,-1099609086,1048597242)+W(5,-1094890059,1046324795,1003815995,-1126686757)+W(6,1013951379,1039425378,-1112788128,-1098419769)+W(7,-1118093753,-1108341356,-1120388747,-1135294247);sum2=W(0,-1112864979,1034721747,-1108077379,1023366533)+W(1,1021246669,1032508120,-1113986367,-1153257254)+W(2,1024004698,-1109416755,988806988,1058238498)+W(3,-1115279539,1041332549,1033457886,1018109285)+W(4,1034996841,1041661735,1041642045,1008174217)+W(5,-1122858630,-1089151778,-1130797677,-1111548255)+W(6,1004307827,-1116757818,1037366938,-1107547239)+W(7,-1108868659,-1128614293,-1130732717,-1122125438);WS(1066216871,-1084582294);
sum1=W(0,1009745022,1023325836,1034246149,-1103455511)+W(1,1025953385,-1105242559,988118663,-1107601837)+W(2,-1095963722,-1096473834,-1087129751,-1142570129)+W(3,-1094684497,-1107829831,-1107520037,-1117719279)+W(4,1050775177,1046303345,1057767679,1064400323)+W(5,1038452388,992534739,1025316967,1044853309)+W(6,1027534757,-1126933960,-1118146623,-1103828265)+W(7,1018950609,1030437560,1020674901,1033139589);sum2=W(0,-1127013105,1018526115,-1123587641,1052346460)+W(1,-1098654594,1029804743,-1118240305,1030491706)+W(2,1031626404,-1117975133,1062148372,1074624908)+W(3,-1090512380,-1070854231,-1095518794,1041467716)+W(4,1029958550,-1113082476,1035325186,-1130733653)+W(5,1046581721,-1113725416,1031776819,-1115594754)+W(6,1017794797,1023300847,-1145491637,1041942663)+W(7,-1113152926,-1139181075,-1120299385,-1142763637);WS(1033725552,-1082653885);
sum1=W(0,1027658456,1033791775,1038169633,-1130834725)+W(1,-1105755912,-1107114253,-1106878767,-1102176852)+W(2,-1091894661,-1094613753,-1085886368,-1094605577)+W(3,1049096200,1038006563,1040399888,1038046228)+W(4,1054730080,1052727904,1060322284,1054915405)+W(5,-1115316932,-1113871235,-1114082704,-1098681477)+W(6,1024810077,1020875129,-1114253244,1021660859)+W(7,1010914050,1032412472,1016596422,1044096992);sum2=W(0,-1126607908,-1111819446,1032709615,-1119610542)+W(1,1027594385,1029384695,-1115269200,1032209203)+W(2,-1109006144,1050929158,1025316173,-1107176811)+W(3,-1123863107,-1122531221,1026796828,-1115616555)+W(4,-1093467963,1063076656,1048889614,-1090320472)+W(5,1046933317,1051206364,997945380,-1109796884)+W(6,1059727060,1073053378,1073749745,1058093447)+W(7,-1079533534,-1073154062,-1075936158,-1088004581);WS(-1087442510,1045166814);
sum1=W(0,-1106921670,1032907600,-1111070674,1047421629)+W(1,-1094092352,1031075349,-1136240762,-1129052086)+W(2,1032009478,-1127325529,-1106321881,-1085655355)+W(3,1057239638,-1098381173,-1128650952,-1107389381)+W(4,1041337656,-1100890040,1060092296,1044767811)+W(5,1040377247,1037296628,-1131454723,1037463686)+W(6,-1110338367,1042108264,-1105899594,1027442111)+W(7,-1105935775,1037469097,1027139781,991481919);sum2=W(0,-1119426781,-1109786529,1041819143,1018220925)+W(1,-1103055916,-1124599508,986571056,1024618671)+W(2,1040351141,1043540747,-1105926532,-1133247980)+W(3,-1096724541,1038612076,1019567362,-1143357456)+W(4,-1104019881,-1106797782,-1098594115,1066013053)+W(5,-1136157126,-1097021086,1025702119,1008181894)+W(6,1015410156,1043466418,1048709183,-1092013542)+W(7,-1109288787,1027934232,-1140871148,1027080058);WS(1059279054,1041683061);
sum1=W(0,1028823114,1033060856,-1136683218,1041097809)+W(1,-1108712682,-1099515041,-1114499693,-1105525449)+W(2,-1096417644,-1095251776,-1096755466,-1095420880)+W(3,-1087904547,-1117180600,-1113115866,-1121084634)+W(4,1041071884,1051348966,-1106154521,1062896338)+W(5,1057053635,1050313119,1041134484,1043053335)+W(6,1040139175,-1133443258,1027763154,1037083176)+W(7,-1109247178,-1169250436,1007514196,1031868218);sum2=W(0,-1104031080,-1113246189,-1124792744,-1107688308)+W(1,-1084040655,-1089958554,-1098618924,-1098033920)+W(2,1039900182,1044206765,1043086617,1057123143)+W(3,1066602722,1037219700,-1111210157,1036938090)+W(4,1028023758,-1122555834,1041018096,-1100462314)+W(5,-1123151815,1032289221,1028867168,-1143651414)+W(6,-1125301559,1027754708,-1129842792,1022410763)+W(7,1034604384,1029558442,-1139711519,-1122704124);WS(-1093886876,-1092780259);
sum1=W(0,1031521076,1040859655,-1123954783,-1115369432)+W(1,1027325374,-1130075936,1017430099,1005655277)+W(2,1034696971,1027092583,1057011018,1055452141)+W(3,1055461116,1043845385,1041326696,1045628689)+W(4,-1098366291,-1107551117,-1084481759,-1086775792)+W(5,1050583573,-1098824964,1032795870,-1110858724)+W(6,991412379,1023411481,1037665034,1037775165)+W(7,-1102735091,-1106471523,-1113156096,-1108701199);sum2=W(0,-1099549152,-1101982776,1039636960,1065032135)+W(1,1046191187,-1112740199,-1120755726,-1138571865)+W(2,-1115620025,-1110046443,1067650764,-1096892917)+W(3,-1084058149,-1089814493,1022618460,-1106519005)+W(4,1042476476,-1138118945,1056117723,-1084935200)+W(5,1043334912,-1116550886,1030169574,-1123579094)+W(6,-1128057356,-1104607948,-1129519972,1039009532)+W(7,1042222420,-1114781123,1023299940,1029490149);WS(-1103384376,1050555318);
sum1=W(0,990997212,-1104723373,-1102560870,-1110645588)+W(1,-1114771100,1006886950,1011892746,1041403778)+W(2,1056616014,1049493908,1060440249,1063537686)+W(3,1049398171,-1123261404,1042753094,1041297647)+W(4,-1113359817,-1101985253,-1095607555,-1091747296)+W(5,-1098384586,-1094355067,-1098733239,-1099641616)+W(6,-1104278389,-1112669305,-1117918862,-1124628967)+W(7,-1120789735,1020875660,1029891897,-1143354303);sum2=W(0,-1097904627,-1102268820,-1101696600,-1102083058)+W(1,-1100977750,1022682138,-1105396681,1035758392)+W(2,1056762738,998260703,1049156882,1055125136)+W(3,1040009482,-1099421122,-1114104451,-1112582051)+W(4,1033294591,-1102966386,1040206209,1048772561)+W(5,1004029807,1040485303,-1118051402,1040482786)+W(6,-1113205081,-1105114179,1028552759,1023069474)+W(7,-1108173489,1040370279,-1109779069,-1135668672);WS(1042369848,-1095650924);
sum1=W(0,1032801852,-1124780413,-1142443027,1031124370)+W(1,1024489633,1037041722,-1157391942,1048283534)+W(2,1060985291,1056066249,1059062488,1046815795)+W(3,1051554984,1026983110,1037131073,1028118439)+W(4,-1088222536,-1093287088,-1089766974,-1084610255)+W(5,-1096293908,1035048291,-1113190096,-1107690581)+W(6,-1154392525,1017158008,1041310978,-1111535759)+W(7,-1118760812,-1118618480,1032589425,-1101944856);sum2=W(0,1056251107,-1118435725,-1111043713,-1090037466)+W(1,-1129656805,-1093926860,1052716525,-1083761792)+W(2,-1084477192,1041984407,-1093515412,1073185178)+W(3,1051712939,1053076395,-1096065312,1066458198)+W(4,-1077785336,-1086371528,-1093010832,1074151927)+W(5,1054463958,-1094829660,-1090812268,1063500158)+W(6,1053829707,-1113013425,1046411943,-1090694669)+W(7,-1095714333,-1103046632,1035367276,-1087950464);WS(-1081634407,-1072784825);
sum1=W(0,-1102740818,-1115394775,-1101924733,-1100839185)+W(1,-1123768914,-1140848016,-1118249725,-1116477425)+W(2,1024862651,1046040367,-1109613465,-1115978107)+W(3,1049722038,-1098661743,-1138059466,1025943000)+W(4,1056867014,1027952685,1058509811,1050187219)+W(5,-1098437541,1033615035,-1143195264,-1132571500)+W(6,1016622683,-1112643478,-1096240139,-1101581667)+W(7,1008822020,1023463264,-1116668435,1036595961);sum2=W(0,-1139809909,-1126178115,1032546581,-1097752958)+W(1,1042272246,-1118367610,-1138081685,1017774855)+W(2,1046126277,-1111752353,1034216546,1042101074)+W(3,1043290796,-1112722386,1034532478,1030093406)+W(4,-1119940899,1055245806,-1088954301,1058677046)+W(5,-1087007443,1048637958,-1140548675,1029648824)+W(6,1040903120,-1104413152,1019748625,-1089277711)+W(7,1028591970,-1139620757,1017306737,1033828758);WS(1050645916,1033550915);
sum1=W(0,-1118556120,-1108262319,1043230361,-1094947334)+W(1,-1103841584,1018079143,1032598742,1008731683)+W(2,-1107219907,1043545243,-1086762442,-1104041435)+W(3,1058293794,-1097977901,1041130248,-1123331655)+W(4,1039060494,-1145250020,1059123936,1057758321)+W(5,-1096913490,1039599795,-1151122424,-1123961290)+W(6,1030703933,-1110184190,-1110311564,-1100512367)+W(7,1044416908,-1132472896,-1147952664,1022228292);sum2=W(0,1040267615,1048409433,-1107165984,-1086251247)+W(1,-1113957324,-1107976602,-1122078587,-1111525785)+W(2,-1112791644,-1110540665,-1088877638,1053330884)+W(3,1057377190,1057673067,1024512949,1042772014)+W(4,1010515766,1032365064,-1090038325,1049266570)+W(5,1028890653,-1103454662,1041725883,-1143554104)+W(6,1024308395,1041630361,1040244783,1037513285)+W(7,-1098504745,1039941233,-1103661415,1024552651);WS(1051978908,-1102077462);
sum1=W(0,-1132165009,-1117187439,-1108837850,1037183202)+W(1,1028473682,1045655273,1025240990,1033734537)+W(2,1045761591,1051430047,1060286099,1046972447)+W(3,-1128782822,1028047735,-1178179968,1035331372)+W(4,1013540534,-1096198150,-1130717861,-1085387922)+W(5,-1105434962,-1101497054,-1110960744,-1102517015)+W(6,-1106078467,1014010165,-1121999817,1030141582)+W(7,1008925446,1018887490,-1122721428,1026996307);sum2=W(0,1023072493,-1125531833,1030396885,-1118880502)+W(1,1027419877,-1161271853,1019485964,1028708277)+W(2,974611657,1047662948,1035351326,-1090109833)+W(3,-1110942359,1033315833,1010290822,-1156901930)+W(4,-1101792417,1051899312,1080526024,-1069022098)+W(5,-1087739606,1036440530,-1124554651,-1114394737)+W(6,-1112121991,1037288067,1042102238,-1113214479)+W(7,1032127295,-1143368203,-1132377096,-1141169667);WS(1058455886,-1096183470);
sum1=W(0,-1105360672,-1112035684,-1105059667,-1103063975)+W(1,-1112638549,-1104182327,-1106250503,-1103319623)+W(2,-1112611850,1032735242,1048808633,1042817013)+W(3,1058906409,1047248804,1047193699,1057710235)+W(4,1060616064,1033545283,1051085625,-1097442806)+W(5,-1102188695,-1103229812,-1106970890,-1109193562)+W(6,-1104075433,-1111940643,-1115570744,-1097216429)+W(7,-1107200030,-1108265532,-1119499692,-1106901731);sum2=W(0,-1135393651,-1131009665,1004138181,-1111055824)+W(1,-1134829555,-1127256265,-1113946573,1010148467)+W(2,-1114274101,1016197705,-1143366053,1051632163)+W(3,-1111579981,1038147066,1025185617,-1137859715)+W(4,-1117767149,-1130986601,1026922589,1048764370)+W(5,1036257166,-1112945554,-1143942149,-1123068365)+W(6,-1110403581,-1136444051,-1112183743,-1121253595)+W(7,1009689523,989872074,-1123668797,-1123716033);WS(-1103618872,1023577831);
sum1=W(0,1041702149,1032268701,1021026046,1032012647)+W(1,1023662430,-1111766616,-1112590149,1042231991)+W(2,1057806109,997904496,1057675340,-1129702414)+W(3,1056283152,1039716321,1049875952,1054291708)+W(4,-1091063799,-1106010126,-1090884608,-1094077941)+W(5,-1094732237,-1100869456,-1105996279,-1098425069)+W(6,1022049043,-1102660926,1046995709,-1100395542)+W(7,1050214494,-1096243374,1047647816,-1100607928);sum2=W(0,1073849383,1069429154,1070121938,1066905653)+W(1,-1087755842,-1080359597,-1073496568,-1070245916)+W(2,-1072987051,-1080077361,-1076996297,-1086754234)+W(3,1060194671,1067521081,1074652354,1075883836)+W(4,1040644897,-1098556311,-1124122091,-1095882058)+W(5,-1096747545,1048551041,-1092793409,1058695504)+W(6,1022236877,-1128073567,-1118780260,1027638421)+W(7,1012182550,-1129108935,-1130588931,1001812541);WS(1010873216,-1100304815);
sum1=W(0,-1154187044,1028741017,-1114247598,-1099084427)+W(1,-1104966895,994968800,-1113228468,1028263947)+W(2,1045945805,1051026373,1058185854,1059904750)+W(3,1052860588,1038231664,1040557287,1032103905)+W(4,-1102222630,-1103217414,-1097780567,-1091550752)+W(5,-1108718914,-1110664976,1017403508,1017865354)+W(6,-1113759340,1022415534,-1105383733,-1111624796)+W(7,-1114326870,-1110217221,-1108875519,-1109350878);sum2=W(0,-1114639192,1039210963,1047528380,-1099502544)+W(1,1041344628,-1108972702,1021595805,-1116883371)+W(2,-1100331344,1069298433,1080352854,-1067747068)+W(3,-1080996124,1032407437,-1121090437,1016604711)+W(4,1035901690,1043940791,1030733380,-1084572959)+W(5,1003800555,1045939813,-1121287047,-1122259179)+W(6,1012858414,-1126620651,1036529177,-1099630936)+W(7,1043527822,-1119860547,-1145664907,1034105585);WS(1044302648,-1104457270);
sum1=W(0,-1115179413,-1101763748,999269803,-1106420033)+W(1,1041707045,-1128885581,-1110751840,1029110244)+W(2,1029190781,1045938783,1034810490,1055724168)+W(3,1053359959,-1100033022,1037908026,1035419021)+W(4,-1108944696,-1102720380,1038235218,-1101615303)+W(5,-1094303566,1043259278,1011056201,-1123807773)+W(6,-1115207128,1013266237,1025157307,-1105407492)+W(7,1045691477,-1113033137,-1114066571,-1113282394);sum2=W(0,-1117238549,-1115295266,1033754662,-1095438097)+W(1,-1106855439,1011060498,-1117460606,1032653312)+W(2,-1109414288,-1128441429,-1104877135,1053172955)+W(3,1056926069,-1108715476,1036225840,-1114450934)+W(4,-1115125848,-1121954754,1018153798,1038786210)+W(5,-1104082080,1043675119,1008366234,1018894269)+W(6,1023475415,1024122972,1002646200,-1106263750)+W(7,1034246226,1025499367,-1107090094,1013321052);WS(1068015911,1043072951);
sum1=W(0,-1127841379,1035792844,-1155603908,1018341976)+W(1,-1111053022,1044403491,-1112313859,1005208661)+W(2,-1101991257,-1091973141,-1110119406,-1095315357)+W(3,-1107228151,-1111437840,-1097295811,-1103670736)+W(4,1041159238,1040826438,1052691071,1053842800)+W(5,1042506601,1050221764,1030249017,1046985745)+W(6,1035382295,-1098419575,1043898844,1030324599)+W(7,-1108241413,1043481954,-1098652336,1032196534);sum2=W(0,-1134315530,1033824390,-1112867968,1039862799)+W(1,1005143468,-1114969920,1030354102,-1131720457)+W(2,-1125722365,1019923991,1039464885,-1087456726)+W(3,-1119378177,1042059959,-1113780490,1009971850)+W(4,-1135384490,998580556,-1093291922,-1061395777)+W(5,-1106942114,-1121281813,1034179020,1032010553)+W(6,-1118933131,1027495017,1045077367,1087627027)+W(7,1034637079,-1148550692,-1118611519,-1117397469);WS(1060186318,-1131602669);
sum1=W(0,1022422466,-1102049002,1050775273,-1097141731)+W(1,1056872997,-1099566807,1025667942,1032894309)+W(2,1050205114,1052887138,1052456073,1049038746)+W(3,1040490435,1039690728,1043457059,1045856748)+W(4,-1099402401,-1102238785,-1100510367,-1088759247)+W(5,-1122526498,-1099089908,-1102859210,-1106963501)+W(6,-1112848707,-1106285089,1039607513,-1098786589)+W(7,1048305743,-1104192622,1032266998,-1118572779);sum2=W(0,989650422,-1108234271,-1120122674,1045260201)+W(1,-1114112879,1037831837,-1117501250,1024132690)+W(2,-1120410947,1050158699,-1092804082,1024838498)+W(3,-1125280065,-1119936776,-1114421818,1035095434)+W(4,1047633630,1066272871,1075424781,1061734347)+W(5,-1091697647,1003481288,1011848513,-1106020023)+W(6,-1081060940,-1074101109,-1079387458,1050344942)+W(7,1043540897,1039609275,-1131708367,1026462111);WS(1057810382,986287880);
sum1=W(0,-1105255365,1027767677,1037147968,1038550632)+W(1,-1136315263,1035749561,-1115075413,1028257967)+W(2,-1110142276,-1106138450,-1092238936,-1090210593)+W(3,-1089134184,-1093055129,-1097497096,-1089420006)+W(4,1041191503,1031406779,1027980992,1049547413)+W(5,1052451129,1057536820,1050343212,1058108487)+W(6,1050176972,-1130243957,1041310918,1041377527)+W(7,-1115128119,1033537239,-1127231554,1031965752);sum2=W(0,-1099824579,-1113793286,1053512844,-1112943238)+W(1,1041834894,-1099992002,-1120789532,1024916046)+W(2,1070708271,-1104040400,-1091831853,-1072548459)+W(3,-1093778092,1057576575,1064181862,1051972140)+W(4,1075074245,-1084124078,-1082668198,-1072503695)+W(5,1056090411,1053907302,1058602971,1054786345)+W(6,-1097074436,1023561426,1039380165,1009216489)+W(7,1043969626,-1107563771,1034348623,-1106961801);WS(-1075707047,1038147646);
sum1=W(0,1038492938,-1115961531,1036899040,1041066756)+W(1,1038870159,1045702796,1022987667,1044017707)+W(2,1050722763,1026800423,1055626176,1052178217)+W(3,1027667391,1053246416,-1100305296,1049962981)+W(4,-1095596015,-1103730686,-1091210886,-1090286882)+W(5,-1094135001,-1095582752,-1109653838,-1093296229)+W(6,1040870942,-1122935577,1047700685,1036539085)+W(7,-1102625947,1048523811,-1105859960,-1117734303);sum2=W(0,-1145353723,-1113260796,-1112198364,-1113367096)+W(1,1007958125,1047146251,-1122974002,1021064313)+W(2,1027969677,-1095928859,1052169305,1052353113)+W(3,-1129450520,1051473061,-1091037095,1050393555)+W(4,-1115030411,1031463199,-1108227013,1051016428)+W(5,1041462653,1045242344,1032341221,1020102815)+W(6,1052090154,-1110261785,1041877601,-1099630700)+W(7,-1087173862,-1102681887,-1095485390,-1111896409);WS(-1102302520,1068562064);
sum1=W(0,-1130894152,1029216267,1029150351,1029804895)+W(1,-1108054071,1046304488,-1107326720,1018120580)+W(2,-1101486038,-1094978851,-1104755260,-1093484995)+W(3,-1110271975,-1106599349,-1102131284,-1102274525)+W(4,1044130034,1029251017,1053252560,1050941559)+W(5,1036880709,1050863202,-1128083416,1047248574)+W(6,1031789673,-1102217970,1042516209,1040658618)+W(7,-1113036417,1041743615,-1102226940,1032422999);sum2=W(0,1019111797,-1123809812,1006739898,1041109085)+W(1,-1126211453,1028972357,-1118372569,1025713585)+W(2,1022527979,-1111065998,1031759809,-1095097056)+W(3,1034613952,-1107360163,1033659253,-1118642675)+W(4,-1131519898,1023737355,1045357020,1082939698)+W(5,1027342607,1033832936,-1112248823,-1118824157)+W(6,1029130971,-1117143513,-1106220344,-1064938697)+W(7,-1122955245,-1112280546,1032152906,1028082979);WS(1066566439,-1125753148);
sum1=W(0,1020091828,1041951168,-1130301450,1052053147)+W(1,-1131231944,1033588155,1009411772,-1116682291)+W(2,-1096367972,-1098758994,-1093467737,-1089881409)+W(3,-1092544881,-1098181717,-1110070786,-1096392077)+W(4,1038767583,1048997640,-1130818632,1064063659)+W(5,-1116991019,1042770882,1046860728,1027361773)+W(6,1030663671,1025331919,-1108818909,1044746920)+W(7,1022962726,1041997189,1018371147,1038578846);sum2=W(0,-1105507764,-1149004498,-1098298748,-1115729482)+W(1,-1094576030,-1111478010,-1129010369,1018600957)+W(2,1019815533,1047279899,-1106660204,1058550934)+W(3,1031191852,1032716298,-1117054989,1019851909)+W(4,-1136431769,-1121679526,-1096656341,1058580319)+W(5,-1098228632,1041490224,1047791827,-1106522387)+W(6,1024962860,1041000955,-1107413740,1027135608)+W(7,-1101441076,1035067556,-1123460834,1005788722);WS(1050996380,1066787661);
sum1=W(0,1042843177,-1120310187,1033453959,-1107450543)+W(1,1017862620,-1134072575,1025308393,1033769739)+W(2,-1109518091,1043911830,1059519229,1061971625)+W(3,1051823058,1046601317,1042112788,1046863997)+W(4,-1098674409,-1097687209,-1096304487,-1098011863)+W(5,-1095767039,-1095249970,-1098354285,-1098417599)+W(6,-1112832565,-1133582755,-1116528532,-1105396874)+W(7,1033796902,999923683,1030029487,-1109771063);sum2=W(0,-1103321099,1033376724,-1108916223,1033194077)+W(1,1038197771,1032881798,1017830932,-1138730935)+W(2,-1087654445,-1114493691,1049058628,1065240604)+W(3,-1128335788,-1094150295,1006224046,-1112103411)+W(4,-1098379129,-1096458683,1036368268,1054396447)+W(5,1049730119,-1108472207,1031462702,-1102017203)+W(6,1013739975,1015354012,-1121134774,-1115257551)+W(7,-1129699908,1021079748,-1117224382,1038189385);WS(1027314912,-1081149641);
sum1=W(0,-1109480125,-1114947760,-1101195017,-1132100201)+W(1,-1103759537,1044342469,-1111893319,1051194426)+W(2,1051429188,1053252314,1058130398,1061393767)+W(3,1057940398,-1104522586,1055491172,-1120202825)+W(4,-1118844062,-1094077252,-1113091794,-1085308129)+W(5,-1102037735,-1094497965,-1103334896,-1094870250)+W(6,-1097611416,1034118735,-1104617542,1035982720)+W(7,-1114189097,1036294793,-1128796810,1030785028);sum2=W(0,-1131039707,1024995350,-1104486127,1015537291)+W(1,1053996441,-1103676904,1047124046,-1111129691)+W(2,-1098833779,-1124760267,-1078713050,-1065942779)+W(3,1047686732,1084085461,1064521940,-1093915430)+W(4,-1147567565,1057070390,-1091843304,-1081156610)+W(5,-1094140189,1060423478,1046849692,1018309905)+W(6,1035790053,995065627,1037354874,-1154356731)+W(7,-1107145709,1026796886,-1108476011,1038591472);WS(-1081542375,1044780323);
sum1=W(0,1026864081,-1100303790,1048337215,-1098110473)+W(1,1054474587,-1099969099,1023999910,1028627178)+W(2,1046719985,1054288460,1054459103,1048901488)+W(3,1041639871,1034589376,1043694031,1046235480)+W(4,-1098857847,-1108679899,-1098101851,-1093175556)+W(5,-1104037973,-1107626335,-1101510966,-1106600025)+W(6,-1114219435,-1104586877,1041408644,-1098306531)+W(7,1046672715,-1104199322,1022681657,-1126646775);sum2=W(0,1017985090,1027847194,1036519222,-1113167123)+W(1,1037009826,-1113380621,1031131596,-1115360802)+W(2,1024212320,-1098721130,1050387030,-1094712479)+W(3,-1100822056,1028269032,1009055356,-1113841920)+W(4,-1099849981,-1081468176,-1070464929,-1096550174)+W(5,1057690620,1042714784,-1145638655,1046010973)+W(6,1067245211,1074345814,1070597407,-1088417301)+W(7,-1104880956,-1102737214,1000105719,-1112342255);WS(1059294542,1020616832);
sum1=W(0,-1157534552,1039080142,-1097783100,1031217968)+W(1,-1164216296,-1138897989,1026686634,-1105498094)+W(2,-1096856701,1044861738,-1089052876,-1085780263)+W(3,1044573672,-1097342660,1041475528,-1105558033)+W(4,1050532499,1041652423,1057029426,1047119538)+W(5,1039715347,1043073721,1040308239,1048391538)+W(6,-1112831597,1046540791,-1098369827,1040272239)+W(7,1024931118,-1103025619,1045404192,-1114523696);sum2=W(0,-1106291706,1001372950,-1099590495,-1093748925)+W(1,1015225205,-1105937891,-1112612361,995169980)+W(2,1040318024,-1105705183,1045484852,1061316313)+W(3,-1098311584,1041085521,1028378294,1035732349)+W(4,-1114208076,-1116263519,-1108179199,1049891427)+W(5,1040668388,-1111581107,-1115787941,-1113959318)+W(6,-1142193319,-1145917455,1036599633,-1108356360)+W(7,-1148092276,1032743264,1021281994,1024794158);WS(1059376718,-1137270291);
sum1=W(0,-1118257199,1037392427,-1097794403,1035766677)+W(1,1026067385,1032186693,-1108679762,-1139304576)+W(2,1043258576,-1106073464,1054680411,-1099046488)+W(3,-1088020070,1041392887,-1113652045,-1111666975)+W(4,-1114290826,-1124279079,-1115190716,1052189312)+W(5,1054691490,-1097245116,1025610423,-1123561026)+W(6,-1112002778,1022160871,1045843716,1011458515)+W(7,-1110958220,1046761570,-1117145658,1032305501);sum2=W(0,1025244035,-1122852568,-1092220395,1038019467)+W(1,1048072683,-1113553750,-1119930901,-1139793711)+W(2,1033595807,-1087687504,1066421651,1047700223)+W(3,-1084925862,1050883425,-1105555859,-1146566911)+W(4,1016573022,1048825911,1058107887,-1089540205)+W(5,1045215493,-1098430697,1041208433,-1124843514)+W(6,1002397687,-1104089806,-1130145014,-1111655831)+W(7,1032935415,1015641098,1001885951,-1131703250);WS(1058596686,1013962118);
sum1=W(0,1000024554,-1127551432,-1100000762,1035333436)+W(1,-1122612871,1044766998,1041477861,1051562743)+W(2,1052551424,1049056438,1057499982,1036076760)+W(3,-1127972943,-1116046252,-1118015335,-1099275107)+W(4,-1088298614,-1098656348,-1090756927,-1097067922)+W(5,1040213184,1015197910,-1123679237,-1122278672)+W(6,1039656505,1034731345,1019232187,1033429441)+W(7,-1125045580,-1113717771,1037833508,-1122272135);sum2=W(0,-1104434141,1029025211,-1078497608,-1079110377)+W(1,-1085502108,1066279808,1062913146,1068620036)+W(2,1048601996,-1091369704,1052827694,-1106615386)+W(3,-1115334546,1037382016,-1122817088,1048688798)+W(4,1033271157,-1119340081,1025214064,-1109539756)+W(5,1050957039,-1106594885,1036274829,-1118139306)+W(6,1004930429,1028438774,-1106316897,1034989376)+W(7,-1108631008,1023198169,-1134348613,-1139733884);WS(1044771128,1023341948);
sum1=W(0,-1156220044,1034545464,1033488922,-1111313058)+W(1,1038420969,1008511890,1013986230,1011084871)+W(2,-1092336191,-1098819215,-1096491302,-1086850728)+W(3,-1102939421,-1100928894,-1115524377,-1089482302)+W(4,1051560294,1044146859,1051910286,1045449190)+W(5,1053458817,1038883707,1012126018,1046748951)+W(6,1036528391,1029114797,1022761170,1029767950)+W(7,1041877300,1034675856,1037411178,1043196317);sum2=W(0,-1071004894,-1080574884,-1089987082,1049506323)+W(1,1065282653,1062249589,1060165079,1070844945)+W(2,1076503146,1066884159,1058011283,-1098882467)+W(3,-1084978169,-1088626314,-1082249713,-1077734377)+W(4,1057610169,-1107351326,1054000347,-1090234844)+W(5,1030898490,-1090230279,1044380003,-1096516163)+W(6,-1122913984,-1130255370,1038970611,1014162118)+W(7,-1114000490,1022492087,-1131621088,1013009282);WS(-1111817840,-1134998409);
sum1=W(0,1022731056,1045262352,1044888721,1029818259)+W(1,-1105915720,-1114660906,1027479949,991785104)+W(2,-1102901203,-1094315057,-1085070720,-1111793509)+W(3,1055206544,1046806370,-1123039746,-1136267423)+W(4,1029699069,1052915216,1058770140,1057078063)+W(5,-1095183540,-1097451385,-1112670352,-1114500629)+W(6,1021112442,-1107194439,-1097785743,-1117717150)+W(7,1040740592,1036425016,1005586201,1016465988);sum2=W(0,-1129690332,1030842707,-1123486113,1054087898)+W(1,-1105176966,-1097205966,-1098021434,-1106929221)+W(2,-1113356803,1026318374,1041923626,-1089332833)+W(3,1068558125,-1141184456,-1107728348,-1104288342)+W(4,997943457,-1119512995,1037525758,-1088292904)+W(5,1040210770,1050151959,1018682892,1006954668)+W(6,1015499837,-1180561029,-1144014736,1037328869)+W(7,-1107365912,-1114055561,1009592392,1013301204);WS(-1100650808,1043653943);
sum1=W(0,1038392637,1032036848,-1120772452,1043637149)+W(1,1040259489,1047398869,1038054351,1050576478)+W(2,1044290651,1040683515,-1106266873,-1090111931)+W(3,-1133467790,1044787930,1023591523,1037223428)+W(4,-1095199164,-1115398639,-1094097345,-1097393337)+W(5,-1104941765,-1101572298,1016760834,-1102689443)+W(6,1033771919,1038316223,1042896310,1045751664)+W(7,-1159203906,1015063331,1030908740,-1125005703);sum2=W(0,1018053796,1000548496,1049079603,1039189619)+W(1,-1128574308,-1118597354,-1106984497,-1104543855)+W(2,1046306039,1043541862,1010667960,1064529690)+W(3,1047996002,-1087406141,-1095617964,-1086946593)+W(4,-1101305605,1029064982,-1116813778,1038487223)+W(5,-1100258391,1048794746,-1114392997,1045938007)+W(6,1031448374,-1112893849,1021972628,-1105518867)+W(7,1037842238,1033382833,1021089548,-1140458600);WS(-1121537248,1047151836);
sum1=W(0,-1096325448,-1113135282,-1098188693,-1112146268)+W(1,-1108791588,-1117696601,-1123869651,-1114157115)+W(2,1052654400,1035132488,1046868890,-1134150082)+W(3,-1129891280,-1098847494,1032919412,-1107856679)+W(4,1000450324,-1110395025,-1139200797,1049727010)+W(5,1041189572,1056884317,1041128337,1058220805)+W(6,-1116556387,1023519458,-1111260975,-1110207458)+W(7,-1104838938,-1098805187,-1146298440,-1103148146);sum2=W(0,-1142864271,1021304865,1043366966,-1107584343)+W(1,1014758407,-1130465374,-1120740451,1000478551)+W(2,1043572739,1026011378,-1102859954,-1080136051)+W(3,-1103597159,-1115654645,1046511165,1053224660)+W(4,-1125571574,1028667063,1022196210,-1072538638)+W(5,-1076945816,1048815254,1072551214,1074776028)+W(6,-1107989855,-1140649559,1020722946,-1132367054)+W(7,1041979768,-1126224006,1027667511,1048839210);WS(-1086568910,969651201);
sum1=W(0,-1128189323,1044154939,1043534732,-1114366976)+W(1,-1098469330,-1101372520,-1123038043,-1132910587)+W(2,-1096064919,-1089612648,-1084798775,1053159863)+W(3,1053431542,1050787607,1036747448,-1116020373)+W(4,1047521403,1054908701,1056987371,1057685165)+W(5,-1089249613,-1090701774,-1105030179,1027268120)+W(6,1043461231,-1099266659,-1113308531,-1152040120)+W(7,1042761408,1049635020,1010635844,1018344000);sum2=W(0,1042932965,-1103428495,1039997403,-1093583228)+W(1,1044856824,-1121819542,-1177180368,1028413178)+W(2,-1103892922,1060495074,1052448567,-1075640666)+W(3,1057723154,1057002090,-1112150955,-1118134166)+W(4,-1104364155,1060109323,1064108701,-1073056297)+W(5,1055665788,1060503917,-1116550688,-1110515035)+W(6,-1139842168,-1118896922,991756114,-1097481656)+W(7,1040659602,-1099984054,1034919451,1041069777);WS(-1084093518,-1116656412);
sum1=W(0,1002008836,959481663,-1104590931,1050696243)+W(1,-1106608235,1047962207,1030562773,1015783795)+W(2,1058416208,1026388179,1059097973,1042079029)+W(3,1041679827,1049127990,1031439243,1042535660)+W(4,-1096672513,-1109778819,-1088144465,-1096264126)+W(5,-1101432288,-1100480244,-1113594772,-1093923750)+W(6,-1112390467,1023428581,-1112632704,1040470858)+W(7,-1102954054,1047012782,-1112144502,-1145396437);sum2=W(0,1007960967,-1110192070,1049899326,1056650247)+W(1,1078512141,1081472440,1058404171,999915485)+W(2,1027407916,1010716935,-1097456083,-1070859565)+W(3,-1068241064,-1079514242,-1094427160,1030657127)+W(4,-1129957403,1018303319,1037417999,-1094713389)+W(5,-1096379657,1043613542,1025537830,-1116925932)+W(6,-1132155403,-1121935910,-1137993343,-1142796285)+W(7,1039214170,-1111213656,1032528613,1024356221);WS(1052225948,1018668194);
sum1=W(0,-1120453498,-1123160289,-1108654867,-1104839613)+W(1,1041378113,1036965515,1044186084,1034438594)+W(2,1051775516,1048325451,1058214550,1064670427)+W(3,-1126638409,1049967085,-1096299613,-1128237844)+W(4,-1117579103,-1111291056,-1093397513,-1091445969)+W(5,-1092047898,-1099225050,-1112850625,-1112057991)+W(6,-1107074656,-1112742544,-1147977428,-1119335936)+W(7,-1109154218,1034167881,-1138567959,1019177609);sum2=W(0,-1121001958,-1148685985,1018483434,1021815720)+W(1,1049361594,-1108634723,-1132118692,-1105580672)+W(2,-1117606942,-1111847761,-1120566718,-1076982600)+W(3,1074852012,1048076514,-1102180777,-1116866514)+W(4,-1103097305,1021935234,1049895592,-1081972918)+W(5,1051964198,1040925857,1017568960,1040155911)+W(6,-1130038396,-1112487949,1038078839,-1125812992)+W(7,-1152546434,-1104919092,1026180028,-1123068468);WS(-1096382876,-1091051652);
sum1=W(0,-1116126267,-1113197617,-1112424211,-1124324715)+W(1,-1136579346,1040875430,-1113905512,1017323784)+W(2,1057278592,1048826126,1058810754,1056304110)+W(3,1041995897,1016295122,1024916389,1042534003)+W(4,-1096000788,-1097274020,-1088739494,-1091311905)+W(5,-1114916522,1038826452,-1128507781,1017648027)+W(6,-1116910752,-1140807037,1039925053,-1132679170)+W(7,-1107191661,-1119450067,1023437062,-1098370349);sum2=W(0,-1120311657,1036113080,-1109045199,1029662296)+W(1,-1122358251,-1114085873,1016737279,-1115835645)+W(2,1025682064,-1107470193,1035621932,-1118009189)+W(3,1045290388,1009830751,1035169596,1030264440)+W(4,1036682152,-1108061877,1051542033,-1101792442)+W(5,-1093646778,1056395710,-1091719234,1052430993)+W(6,-1108273289,1012612647,-1101063214,-1076098595)+W(7,-1080861029,1039398973,1065137390,1072502688);WS(1040082544,-1114755812);
sum1=W(0,1017784372,1037505264,1045745417,1019379817)+W(1,-1109308706,-1124056118,1025470519,1039469090)+W(2,-1110974758,-1108514902,-1095324708,1052579502)+W(3,1058051822,1046163210,1038459986,998280780)+W(4,1040296296,1041424680,1054913780,-1106396419)+W(5,-1087512533,-1093666877,-1106674096,-1109356390)+W(6,1024480479,-1104471944,-1106439461,-1115066496)+W(7,1040857799,1001482384,995688529,-1108404770);sum2=W(0,-1162396366,-1117720653,-1104226850,-1105580348)+W(1,-1105643813,1031813906,1011045214,1018164327)+W(2,1045315846,-1118054954,1057942904,1059476362)+W(3,-1090022037,1045409162,-1106412098,1023977529)+W(4,1034748092,1034773210,1043388435,1067689202)+W(5,-1083232471,-1101262587,-1124577575,-1102021751)+W(6,1035646876,-1100298043,-1097646834,-1093789486)+W(7,1040357620,-1113573448,1012935222,1024454049);WS(1036525168,-1082462584);
sum1=W(0,-1116308971,1037298441,1027885589,-1122874917)+W(1,-1154089797,-1108384819,1028179743,1003463273)+W(2,-1085123800,-1087372070,-1086414101,-1096064460)+W(3,-1099879381,-1104319094,-1127380522,-1096394215)+W(4,1057675329,1051660338,1059597873,1059581688)+W(5,1052784510,-1117339864,1039251609,-1110971807)+W(6,1019612704,1027541711,-1109257541,1041073820)+W(7,1028059367,1045372305,1031554934,1053758651);sum2=W(0,1060691160,-1103295177,1035985281,-1085964582)+W(1,-1105398566,-1107551093,1049030608,-1090293163)+W(2,-1081285622,-1090050073,-1102851017,1072728426)+W(3,1060511611,1033954581,-1086630634,1058069039)+W(4,-1080809247,1050684042,-1087522637,1060852217)+W(5,1058511518,1041242888,1028348456,1062481845)+W(6,1052276353,-1106187369,1048638013,-1090587145)+W(7,1029176048,-1094879840,1046256182,-1087039462);WS(-1074352935,1040600857);
sum1=W(0,1042034194,1028652336,1024054004,1030695172)+W(1,1029627411,-1117605317,-1114002447,1041624512)+W(2,1057627204,1025049468,1057567995,1022098295)+W(3,1052602222,1039437212,1049556590,1053416947)+W(4,-1090157751,-1105875707,-1088931067,-1095088235)+W(5,-1094832321,-1104356174,-1107260676,-1101255271)+W(6,1024364622,-1105990299,1048022018,-1100928004)+W(7,1049957878,-1095846092,1047165477,-1098759166);sum2=W(0,-1075440350,-1079714919,-1079134350,-1081735031)+W(1,1055569671,1066585571,1071644179,1075476470)+W(2,1073165865,1065983198,1068716226,1066499710)+W(3,-1095308006,-1080754250,-1074800849,-1073191304)+W(4,-1112383192,1048707236,-1135853868,-1098543278)+W(5,1021808504,-1108920844,1050977418,-1090378667)+W(6,-1148975848,-1115591486,1038054064,-1125971282)+W(7,1040311395,-1110109816,1035370814,-1120408347);WS(1041022776,1033480094);
sum1=W(0,-1132576057,-1123321429,1028959481,-1104176578)+W(1,1046472198,-1121060138,1027556403,-1115611836)+W(2,1026327841,1042302896,1052457903,1063677500)+W(3,-1097607903,-1123802109,-1118671609,1039698959)+W(4,-1110434490,-1109312954,-1089918670,1025377120)+W(5,-1090934974,1046523967,-1112257611,1000531209)+W(6,-1119031508,1021323174,1029242558,-1118638740)+W(7,1013298461,-1106699146,1030036314,-1116635705);sum2=W(0,-1106027239,-1122286155,-1102546078,1055155948)+W(1,-1096754888,1032068992,-1121774513,1036170969)+W(2,1049930690,-1127267122,1041115945,-1091935564)+W(3,1052250618,-1103388917,1038737216,-1108790214)+W(4,-1110218398,-1108798456,1058786995,1075372513)+W(5,-1071163371,-1123143101,-1121707895,1032355550)+W(6,1034564779,1018367610,-1095860458,1043590800)+W(7,-1112711414,-1119323979,1016553114,1017858173);WS(1055618972,-1117202987);
sum1=W(0,1030962480,-1101414710,-1098100923,-1111740150)+W(1,1036980413,1041005827,1021681163,-1112834597)+W(2,1039894129,1053882576,1057347458,1049814740)+W(3,-1090053902,-1088233382,-1105970903,-1117339136)+W(4,-1101932469,-1089999221,-1085784352,1051098296)+W(5,1056052448,1051763396,1044301630,1032801282)+W(6,1031993659,1048656807,1043352452,1031031542)+W(7,-1104607674,-1119077705,1022017143,1039235901);sum2=W(0,-1114659327,-1123577690,1042921002,-1105097716)+W(1,1042773509,-1093975266,1032061179,1000405669)+W(2,-1101541229,1043634319,1066882360,-1077668162)+W(3,1037629509,1058638399,-1108208741,-1131856909)+W(4,-1107338771,1057974128,1050113378,-1080704784)+W(5,1051155360,1052705661,1008396554,-1111189711)+W(6,1039378885,-1111523166,1040130625,-1104122760)+W(7,1012227066,-1110420726,-1125218199,1025207949);WS(-1091387548,-1116324289);
sum1=W(0,1026642697,1044682252,1041967213,1032214050)+W(1,-1131062694,1015214154,-1137069945,-1110158325)+W(2,-1112220622,-1093973688,1046046637,-1086442024)+W(3,-1099996941,1053177927,-1098783494,1037567917)+W(4,1049897926,1047211372,1050365286,-1112122925)+W(5,1046223135,-1132096750,1024489425,1042021623)+W(6,1027958127,-1098544270,-1112662293,-1106755108)+W(7,-1116559746,1034258897,-1111108842,1031638516);sum2=W(0,-1108095393,1016776222,977935538,-1122468710)+W(1,1019959206,1030099429,-1104930054,1002749526)+W(2,1011776651,1024100809,-1097248934,1057627889)+W(3,1042194141,-1117226417,1051928720,1041814459)+W(4,-1101257730,-1105403134,-1101986254,1060632600)+W(5,-1090719303,1037412790,-1109292621,-1115385474)+W(6,1019145070,1032882678,-1124027994,-1103033100)+W(7,1039533068,-1110127978,-1125661478,-1108291818);WS(1057965518,-1118811194);
sum1=W(0,-1104352985,1038892389,-1105058276,1042490232)+W(1,-1121521774,-1099594944,1033536020,-1095161930)+W(2,-1106566686,-1112643723,1026830542,-1091938531)+W(3,1058056073,-1101314965,-1098044778,1039936570)+W(4,1052732873,1003767366,1060358287,1019887594)+W(5,-1118338013,1042464324,1024562028,1046000094)+W(6,-1107147458,-1114250980,-1096574819,1048844541)+W(7,1024329053,-1107780158,1032778872,-1107207172);sum2=W(0,-1116205334,1042905425,-1109155755,1044205280)+W(1,1035597621,1008636092,1036458751,-1092853308)+W(2,993944814,-1113078065,1044406596,1040105843)+W(3,1043112037,-1123380436,-1105268129,1005260887)+W(4,1032713731,-1104977559,1048672381,-1104277422)+W(5,-1103087244,-1153474446,1015784078,1036094123)+W(6,-1106373772,1039619019,-1115343154,1048332350)+W(7,999501191,-1106439836,1021528398,-1106473413);WS(1053420700,1049909457);
sum1=W(0,-1115258034,1034071238,1027276239,-1115686559)+W(1,1041096236,-1102788144,1034068157,-1107460367)+W(2,-1106165874,-1089903413,1036166247,-1100423414)+W(3,-1093491554,1049835542,-1095323722,-1110396954)+W(4,1050401361,1041332866,1049384898,1037380859)+W(5,1052388787,1034784425,1031952854,1050882791)+W(6,-1113250117,1023742249,-1130552842,-1120158506)+W(7,1037333727,-1103514783,1037170040,-1114330639);sum2=W(0,-1112500393,1028289272,1049127312,1086771603)+W(1,1048088739,1020087240,1014851096,-1146529543)+W(2,1024557142,-1165623582,-1095250820,-1062269001)+W(3,-1095068995,999933935,-1135945992,1025716258)+W(4,-1136367764,1035333264,-1114028070,-1087155359)+W(5,1022077560,1034746908,-1120864651,-1127622484)+W(6,1020782048,-1122738507,1025362120,1034731082)+W(7,-1125007838,-1120796207,1026594640,-1128255426);WS(1063806286,1027083983);
sum1=W(0,-1114823180,1030313470,-1111791457,-1111977289)+W(1,-1108043857,1019729830,-1114640622,1033983240)+W(2,1045480194,1039206373,1061885616,1050451993)+W(3,1057912708,1036575619,1039765761,1034424532)+W(4,-1118427516,-1106496703,1010686340,-1083830979)+W(5,-1099420545,-1105267089,-1131920190,-1125840468)+W(6,-1109705966,1020453816,-1103432478,1039658735)+W(7,-1114670584,-1109909656,-1113587473,-1112770081);sum2=W(0,1033978022,-1100194899,1033701105,1050426550)+W(1,-1104028404,1034191613,-1141130302,1010895851)+W(2,-1122290634,-1091664523,-1071413373,1075108998)+W(3,1062092502,-1103668501,1034149895,-1140709165)+W(4,1016780797,-1103111994,1047766898,-1096749849)+W(5,1027350687,-1131589290,-1131724600,1027888251)+W(6,-1164938552,1002490582,-1105595809,1051489664)+W(7,-1108336227,1021076655,-1149103768,-1131210373);WS(1058288590,1045994186);
sum1=W(0,1018135640,-1123855059,1040223430,-1112801779)+W(1,1036317947,-1098800665,1034707665,-1096517871)+W(2,-1093342072,-1096797372,-1086390197,-1105293320)+W(3,-1091216419,-1117054299,-1096209979,1023470716)+W(4,1052167946,1041780692,1052872019,1059840396)+W(5,1051866430,1050341107,1048652350,1050625648)+W(6,1038262801,1015346466,-1132654257,-1134794696)+W(7,-1117665797,1012611090,-1139713758,1010858330);sum2=W(0,1041114210,-1099284356,1038292116,-1092208278)+W(1,1054381469,-1104534119,1025804573,1033400256)+W(2,-1099008397,1047276236,-1081084758,-1071665325)+W(3,1054365119,1081581342,1062322644,-1093538640)+W(4,-1123917868,-1111523652,1037708884,-1086778305)+W(5,-1101037019,1026238413,-1134916894,1052085127)+W(6,-1125418381,-1120564910,1020505319,-1100128811)+W(7,1024474915,-1125603475,1025011807,-1103707544);WS(-1088887374,1070119449);
sum1=W(0,1040460421,1041554590,1013850612,1038262022)+W(1,1042710919,-1106869091,1044864290,1046057615)+W(2,1052058645,1048371361,1048732808,1042754705)+W(3,1047384127,1054439312,1032508990,1042772520)+W(4,-1090595183,-1115426747,-1094790815,-1087902678)+W(5,-1106656361,-1090477876,-1122940954,-1091795237)+W(6,-1105506686,1029097335,-1129317061,1001782464)+W(7,1038072126,-1131475029,1028935005,-1119515740);sum2=W(0,1024604999,-1112923336,1027433809,1025504127)+W(1,1007245204,-1144581942,-1129047399,1021294865)+W(2,1056461606,1030035123,1050727550,-1090534096)+W(3,-1105339223,-1095507508,1043793174,-1095638178)+W(4,1071685965,1066713447,1068313262,1028028856)+W(5,-1081367671,-1078816510,-1081156501,-1090770344)+W(6,-1075212110,-1080779344,-1078194918,-1153515923)+W(7,1068056044,1069903211,1064173276,1060536751);WS(1040470840,1011790950);
sum1=W(0,1015095158,-1120734562,-1116691398,-1118217942)+W(1,1019898057,-1123629847,1034607368,1041822001)+W(2,1043725275,1051465082,1058372660,1055309890)+W(3,1046636817,1044874098,1043010193,1040878843)+W(4,-1105535856,-1108441440,-1095343471,-1081260869)+W(5,1047492563,-1093096561,-1105294873,-1106259483)+W(6,-1108386992,1030149375,-1112701741,1026499745)+W(7,1032201014,-1115283258,1028457510,-1112399171);sum2=W(0,1022830461,1021246145,1015115055,-1114703004)+W(1,-1120910531,1015720307,983370825,-1123770073)+W(2,-1117997331,-1110014342,-1111993293,1036613835)+W(3,1023720090,-1117604953,-1120463052,1036937497)+W(4,1037270083,-1125616185,1044158772,1073620398)+W(5,-1076883688,-1087890801,1025754476,-1113287589)+W(6,1023767946,-1130403951,1025796328,1050812248)+W(7,-1112499600,1028283916,-1104874229,1033737696);WS(1058309838,-1101980246);
sum1=W(0,-1118965337,-1098779704,1049071256,-1113399754)+W(1,1026571427,-1110569018,-1131332475,-1128371676)+W(2,-1110907254,1049643561,-1081904943,1042163763)+W(3,1052138696,-1106220306,1025191299,-1129449041)+W(4,1038642111,1038999679,1054751182,1056093093)+W(5,-1083956910,1050507993,-1146247429,1030864044)+W(6,1028903966,-1108240479,1040887994,-1118832415)+W(7,1046797612,-1104697276,-1123883748,1017502086);sum2=W(0,-1137655511,1043191716,-1121349336,-1097517035)+W(1,1046822141,-1129223371,-1116759551,-1124684976)+W(2,-1111106723,1033166752,1033268708,1052576386)+W(3,-1107318253,-1102887232,1040601750,993535634)+W(4,1035105104,-1112822728,-1104857525,1055574555)+W(5,-1114990789,-1121581721,-1152414880,-1107957817)+W(6,-1112318930,1027572041,1035699332,-1097542777)+W(7,-1110157019,1031007843,-1157281192,1025775603);WS(1063710542,-1111213649);
sum1=W(0,1039559517,-1110192145,-1107309859,-1118762901)+W(1,-1108199122,1037245627,-1139769966,1035326852)+W(2,1052251350,1049489370,1058328276,1061120005)+W(3,1049656673,1033876357,1041987905,1045428971)+W(4,-1101160384,-1097695264,-1093740712,-1096321197)+W(5,-1097289639,-1114972772,-1102516745,-1103522251)+W(6,-1113889808,1031901152,-1104513406,-1097003636)+W(7,-1112381384,-1176476024,1022802380,-1115185874);sum2=W(0,1026803387,1021750253,1040812059,-1107480079)+W(1,1041131835,-1115082464,1006187407,1001155939)+W(2,-1115186477,1031459540,-1116326399,1040651083)+W(3,1020594503,1033768858,-1132516997,1015478283)+W(4,999853755,1031446318,1058720440,1071698983)+W(5,1051128601,1034660038,1027131696,1041372466)+W(6,-1112425236,-1106593609,-1086524651,-1075753828)+W(7,-1096266051,-1108942599,-1123360193,-1104453127);WS(1039772272,-1082982873);
sum1=W(0,1039127452,-1106264016,-1104546353,-1145518233)+W(1,1041713673,1044410893,1039725795,1007790526)+W(2,1049032497,1053169593,1060522592,1056693961)+W(3,-1095982984,-1088607916,-1099512929,-1120546088)+W(4,-1098139952,-1088020664,-1087153807,1038834197)+W(5,1053429837,1048228018,1030077856,-1130616150)+W(6,-1155633625,1043520647,1040400554,-1139907193)+W(7,-1104883452,-1103034636,-1134131855,1012687882);sum2=W(0,1032987173,-1102803435,-1097110538,-1101871105)+W(1,-1101555589,-1123533577,-1098769512,1048796624)+W(2,-1092902636,1037122437,-1083842457,1067610414)+W(3,1033006847,1041814167,1045724867,999019252)+W(4,1027660911,1039508875,-1115097563,1067552095)+W(5,-1096151174,1026567371,-1107225085,-1105667947)+W(6,1032111389,-1101516234,1001644292,-1104358647)+W(7,-1145661076,-1104681426,1020958965,1028203943);WS(-1101412664,1073047832);
sum1=W(0,-1113880945,-1123950537,-1109995975,-1123565085)+W(1,-1123728428,1035385983,-1115318676,1010675502)+W(2,1059007377,1047579477,1060416389,1056063051)+W(3,1046383171,1040643140,1033389702,1041003725)+W(4,-1091904865,-1097814305,-1087199740,-1092124214)+W(5,-1099567891,1038341800,-1119557930,1042882861)+W(6,-1133362719,-1131741454,1032803377,-1113780884)+W(7,-1113889390,-1126485237,1012558775,-1096461162);sum2=W(0,1013686761,-1123503757,1035262859,-1115490710)+W(1,1025861040,980681483,-1125276038,-1129892230)+W(2,1030949359,1039110679,-1105775253,1027204409)+W(3,1019519396,-1111394964,1024413043,-1126757058)+W(4,-1109223248,1035635962,-1106751414,1057425426)+W(5,1043312829,-1098000154,1051287795,-1103421662)+W(6,-1132915573,996209923,1029135163,1070858778)+W(7,1067133266,-1098902818,-1083268694,-1073095921);WS(-1103532344,-1105840701);
sum1=W(0,-1106756472,-1106322913,1029810954,-1096389739)+W(1,-1116067305,1035916925,-1105566449,1034505108)+W(2,-1105825052,1053932942,-1086676361,-1098358914)+W(3,1054020609,-1096691570,1051257001,1026552303)+W(4,1050195304,1007328528,1057202097,1054492326)+W(5,-1093369370,1012599092,1027855335,-1101687900)+W(6,1044840709,-1104890465,-1144507642,-1098185309)+W(7,1032208700,1048715303,-1100267787,1050640157);sum2=W(0,-1111707317,-1119262447,1037989791,1056036881)+W(1,-1105645897,1006194414,-1146663095,-1129479912)+W(2,-1101137684,-1109186725,1049211868,-1099242284)+W(3,1038198606,-1118866635,-1109483964,-1114787638)+W(4,-1116414033,-1107841286,1056722210,-1094543747)+W(5,1053421235,-1104714858,-1120693058,-1115357885)+W(6,-1103752872,1034593530,-1110917586,1049861706)+W(7,1030171051,-1103907620,1032413269,1029169157);WS(1045178680,-1115117954);
sum1=W(0,-1102680211,-1123018420,-1116849368,1024407336)+W(1,-1107241006,1026392201,-1107918421,-1123314455)+W(2,1048681528,-1113607536,-1092105355,-1093530556)+W(3,-1096193779,-1102060551,-1102337510,-1095199752)+W(4,1019008549,1040296293,1035615004,1061339424)+W(5,1057711678,1055864515,1045891981,1052562824)+W(6,1008490315,1012835273,1027033246,-1128145511)+W(7,-1103222073,-1110547491,-1110097884,1020395952);sum2=W(0,-1108321996,-1115537892,-1106228104,998645667)+W(1,-1112292909,1035781218,-1111036660,1018530825)+W(2,-1096948503,-1104693583,1047339287,1055675007)+W(3,1049114511,-1100682049,1032758858,-1113969306)+W(4,-1112108000,-1112710060,-1126080161,1051246853)+W(5,1041989299,1025978716,1034053890,-1113712936)+W(6,1026091852,1022753169,-1120501740,-1105262859)+W(7,-1123292948,-1139782977,-1111667328,1033000622);WS(1044590904,1058699692);
sum1=W(0,985175380,1034192409,1020554347,1024014533)+W(1,-1115433194,-1128687821,1008304190,-1115445028)+W(2,-1092606720,-1090621088,-1093618783,-1113905855)+W(3,-1096920415,-1112503613,-1100279725,-1101027255)+W(4,1051210502,1050384326,1055009987,1062574818)+W(5,1054554325,1031218808,-1105751509,-1144235755)+W(6,1009220799,-1109361592,-1117059707,-1128567457)+W(7,1015981863,1039114097,-1127205548,1035507338);sum2=W(0,1036009101,-1117283755,1033667347,-1107239966)+W(1,1034685217,-1128406639,-1123321687,-1125402335)+W(2,-1108619644,1041337919,1012813669,1053310286)+W(3,-1103814148,1029066827,-1109499964,-1123197815)+W(4,1010492213,-1100684466,1015579759,1056064408)+W(5,1050883237,-1113069964,-1098878001,-1096911819)+W(6,-1131279719,1035041542,-1124020763,1025470531)+W(7,1032198922,-1104788458,1024066141,-1108347132);WS(1044030776,-1089132931);
sum1=W(0,1034269487,1032883970,1042439154,1044751430)+W(1,1019707982,1041434446,-1133288904,-1128708109)+W(2,-1093699058,-1097458090,-1086092656,-1078975458)+W(3,1035194756,1038040390,-1131544335,-1101499019)+W(4,1045160768,1050995424,1057188990,-1096290982)+W(5,1032938655,1043682915,1022768458,1043305900)+W(6,1040395197,-1135242887,1040422743,1048952172)+W(7,1042217766,1043586045,1029073256,1044718778);sum2=W(0,1043294282,-1127265324,1035036911,1051203976)+W(1,-1092441683,1037063919,-1095318743,-1096741875)+W(2,-1107262777,-1107127922,1048700262,-1114081637)+W(3,1027047222,-1087538045,1043898666,-1114635611)+W(4,-1132728616,-1133435576,-1115280193,1060204569)+W(5,-1096051714,1059699424,-1091030613,1057805441)+W(6,-1112978295,-1101649503,-1142433873,-1138065032)+W(7,1049542158,1027406094,1036599707,-1117298502);WS(-1083489614,-1078579141);
sum1=W(0,-1113694287,1048897616,-1104500498,1029397720)+W(1,1039983475,-1099529286,1047818144,-1100400745)+W(2,-1091060438,-1104759380,-1089217572,-1096433234)+W(3,-1090900481,-1103761763,-1126261903,-1098862766)+W(4,1048678744,1055607032,1025763911,1056656214)+W(5,1055730826,1039576037,1050842685,1044462332)+W(6,1022130309,1045345264,-1098656951,1045280313)+W(7,1003335600,-1104729181,1045845834,-1124798927);sum2=W(0,1034867092,1036831152,-1155378720,1050005016)+W(1,-1109019109,-1107857756,1025727369,-1105627363)+W(2,-1113896283,1008734783,-1107821706,1036439980)+W(3,-1105188391,-1103852014,-1113326142,1036502992)+W(4,-1089397746,-1143881728,-1090933436,1067046868)+W(5,1074023168,1073004488,1071596064,1068047188)+W(6,1053130734,1048547317,1050664536,-1081990202)+W(7,-1073616958,-1073650181,-1078582463,-1079035066);WS(-1123566816,-1118788492);
sum1=W(0,1034266605,-1136553988,1032767842,-1119057557)+W(1,1032596498,-1138237144,1034235800,1038972738)+W(2,-1131696345,1054570946,1043367745,1057910725)+W(3,1051309065,1050053561,1044754161,1047609962)+W(4,-1102436480,-1101485920,-1093672570,-1081257723)+W(5,-1104247863,-1097237249,-1100737384,-1118734125)+W(6,1029920799,1027694719,1029228634,1038070160)+W(7,1041012541,-1104490509,1036672371,-1101643609);sum2=W(0,1001205015,1006355343,1030505158,-1119701641)+W(1,1039794598,-1107202062,1026836118,-1115440174)+W(2,-1108935456,1048575251,-1114918170,-1088419213)+W(3,1032736312,1045905661,-1116946341,1003805295)+W(4,-1123729961,1037564428,-1096130861,-1068662368)+W(5,1076967646,1068403675,-1104305708,-1124006983)+W(6,-1151981614,-1123825361,1015236500,-1095410362)+W(7,1049774729,-1105335733,1050153445,-1103176791);WS(-1103567160,1051728620);
sum1=W(0,1022317012,-1105517764,-1109296554,1030946149)+W(1,1032988986,-1117957958,1025729823,1009731405)+W(2,1037463598,1027268637,1052072875,-1094107172)+W(3,-1087396213,-1098739651,-1104965205,1017302004)+W(4,-1094952698,-1107670055,-1103880757,1052944567)+W(5,1057943536,1052382091,1036164793,1041821631)+W(6,1033922872,1024776175,1038888053,1043766492)+W(7,-1110506946,-1108829569,-1132271979,1015545129);sum2=W(0,1031290011,-1114551402,-1137203270,1025723227)+W(1,1020823723,-1107112701,-1156747895,-1140368490)+W(2,-1127050317,1026829489,1032334734,-1098446681)+W(3,1041359246,1041376772,1034398482,-1104694439)+W(4,-1113481669,1042490649,1043198364,-1127701979)+W(5,1057793899,-1100591458,-1114292550,1037536680)+W(6,-1080536402,-1076466135,1038797044,1074254195)+W(7,1035340712,-1118262367,1013380262,1032104302);WS(-1106439480,1029090439);
sum1=W(0,1034559195,-1151887836,1020849475,1042053132)+W(1,1043127920,1043814293,1037260390,1043715864)+W(2,1042655458,1030625962,1059377738,-1084013087)+W(3,-1107145304,1032281331,1040913704,1033172451)+W(4,-1102396839,-1115609614,-1089162129,-1083731653)+W(5,1052971191,-1107154457,-1113717087,1017680531)+W(6,1026400220,1035325646,1042909598,1039293086)+W(7,1029716960,1024778063,1028666946,-1130742978);sum2=W(0,-1129107524,-1123636938,-1116921954,1035143287)+W(1,1036996009,1026655402,-1117010042,-1126794884)+W(2,1021999108,-1148550480,-1104180688,1058583951)+W(3,-1112895549,-1116180274,-1131502740,-1138164712)+W(4,1022835844,1016982596,1016773924,1054454385)+W(5,-1097314323,-1099699990,-1132536424,-1129763396)+W(6,-1129901940,-1140398984,1030858450,-1117386658)+W(7,-1108156993,-1118751234,1016259828,-1117013506);WS(1048151864,1059242544);
sum1=W(0,-1122367849,-1121466768,1042165293,-1116044868)+W(1,-1105437493,1037358179,-1125163356,-1111398955)+W(2,-1097114939,-1097911384,-1085899247,1042506911)+W(3,1056857214,-1105063934,-1123578292,-1106114902)+W(4,1043794348,1033810391,1063564267,1042284551)+W(5,-1089674786,1049648847,1021855394,1045389303)+W(6,1026875087,1014185912,-1106211614,-1111561384)+W(7,1040868541,1028107682,-1111395274,1010402126);sum2=W(0,-1139648101,-1108856547,1015236663,-1095822659)+W(1,-1137977893,1038373686,1015865663,1025690243)+W(2,-1110557326,1041627874,1032833232,1054902128)+W(3,-1098765424,-1121592121,-1106594443,-1117564251)+W(4,-1106733442,-1106727608,1048813377,1055403310)+W(5,-1097123375,1045561320,-1106386080,1017823319)+W(6,1039330638,987619817,1025349119,-1095503796)+W(7,1050144719,-1108448514,1041979856,-1105901385);WS(1058511566,1043187024);
sum1=W(0,1042620242,1027981614,1037513401,1050564856)+W(1,1040390932,1044188393,1032851398,1043046140)+W(2,1041476871,1044640335,1039039385,-1085132912)+W(3,-1095196494,-1116362934,-1107832665,-1105825814)+W(4,-1106861387,-1120607404,-1101062960,-1089194338)+W(5,1032203084,-1134658518,1026497359,-1105488567)+W(6,1043942651,1040914531,1040902562,1048598306)+W(7,1019897185,1032634704,1027555603,1032742569);sum2=W(0,-1094808435,-1132385524,-1110994277,1039748829)+W(1,1038866141,1012861192,1030487914,-1132742376)+W(2,-1083260450,-1089624726,-1098133391,1063143581)+W(3,1043371703,1040218148,1012758152,1052570990)+W(4,1041967320,-1102801635,1050258559,1037743779)+W(5,1048943341,-1112998265,1031702418,-1105604919)+W(6,1026111290,1034887813,-1123786474,1033106845)+W(7,-1110363077,-1121754906,1012203560,-1111765769);WS(-1087236686,1061665912);
sum1=W(0,-1115274057,-1116162424,-1104461343,-1093387666)+W(1,-1113556238,-1115159031,-1126942285,-1121543315)+W(2,1023071688,1030200068,1054050807,1067462106)+W(3,1050597447,1031104576,-1121547516,1042315272)+W(4,-1107980923,-1101866270,-1092884195,1056570668)+W(5,1044256537,-1106234576,-1128835891,-1114796114)+W(6,-1119301463,-1128116268,-1109238785,-1095571507)+W(7,-1103733247,-1111522325,-1111458030,-1109780718);sum2=W(0,-1127633710,1024854732,-1123781128,1040493279)+W(1,-1105896535,1033983514,-1122459292,-1120616672)+W(2,1024134807,1020748524,-1117094752,1065417820)+W(3,1047826025,-1102101577,1040101538,-1124130304)+W(4,-1114424195,-1098546148,-1079772750,1059484680)+W(5,-1107504040,1049649199,-1105983778,1041220419)+W(6,-1109129714,1025355297,-1102118069,-1114766469)+W(7,1033237727,-1154145757,1012710689,-1123999628);WS(-1092106140,-1084163121);
sum1=W(0,1036347305,1016904817,1034414494,1040590819)+W(1,1047670567,1030378702,-1114654031,1037868673)+W(2,1049849489,1040213041,1056746079,1048812489)+W(3,-1084779712,1040726752,1033236350,1034988241)+W(4,-1101083230,-1152694122,-1083169173,-1107117385)+W(5,1051667767,-1109066592,1024925978,-1107106473)+W(6,-1106738110,-1115216475,1039797369,1022569263)+W(7,-1112982247,-1125038036,1025136605,-1146668256);sum2=W(0,-1144361879,-1128843246,1005924247,-1104940693)+W(1,-1123234701,1030348431,1032437115,1024671661)+W(2,-1111008682,-1134810723,1041181160,1054697191)+W(3,1052731012,1042931729,-1112071203,-1111460488)+W(4,-1092072719,-1121102479,1045581242,1046555600)+W(5,-1103970223,-1104348933,-1113690885,-1129885552)+W(6,1021883158,-1116668390,-1109114373,-1113715104)+W(7,-1128555074,1032936433,-1136719027,-1114960949);WS(1058637774,-1109876822);
sum1=W(0,-1123254812,1041301297,-1108082435,-1113241451)+W(1,-1110973875,1027216056,1014894339,1019588394)+W(2,1042623060,-1105094644,1059472952,1043969956)+W(3,-1113269955,1026816394,-1130602892,1026167148)+W(4,-1126486401,-1111052512,-1094910408,-1094009726)+W(5,1058531737,-1100061186,1032486130,-1117291247)+W(6,-1112485473,1037949088,1016105496,1038892497)+W(7,-1093047519,1032398170,-1128303438,1021704844);sum2=W(0,1019183838,1031923668,1049015983,-1096362417)+W(1,1005830618,1036998273,-1119396253,-1125844722)+W(2,-1103677237,1026573624,-1101357077,1060010174)+W(3,-1122620605,-1106684685,1023743335,970656667)+W(4,1041385745,1025625867,-1095136476,-1096248497)+W(5,-1115221092,1049273019,-1112424814,1011280453)+W(6,-1115238116,1024201143,1024442030,-1122837727)+W(7,1034369966,1031554545,1004099770,1010302645);WS(1068382951,-1145853862);
sum1=W(0,-1109092968,-1120835030,1015957108,1033165317)+W(1,1015780402,-1098982451,-1106789039,-1105810191)+W(2,-1104283584,-1104742016,-1087137628,-1082841532)+W(3,1048723479,-1119342334,1037068029,998682871)+W(4,-1126224104,1048835390,1060142968,1050512116)+W(5,1050625794,1046183055,1033167819,1042826568)+W(6,-1142984099,1035504970,1044651720,1036256010)+W(7,1040271692,-1112268532,-1115364877,-1113754717);sum2=W(0,1042289605,-1123754179,1040865617,1025996190)+W(1,-1100913998,-1118459936,-1114401734,-1118182115)+W(2,-1105845074,1032442894,-1090127653,1055606718)+W(3,-1104101067,1026136504,1031986833,1045409779)+W(4,-1105090355,-1106552079,-1075116096,1073431719)+W(5,1067916428,1042119939,-1112990087,1031635830)+W(6,1041479887,1028813354,-1087510643,-1084272058)+W(7,1045036562,-1131666845,1021173748,-1131440550);WS(-1115823328,-1115141930);
sum1=W(0,994860217,1043355533,1046651158,1031967699)+W(1,-1112906011,-1139800861,1032268536,1021673189)+W(2,-1096937968,-1093401724,-1082957735,1057829358)+W(3,1054780763,1049387203,1029694230,1032667294)+W(4,1034643656,1045563268,1056739037,1053028032)+W(5,-1085595451,-1100812438,-1112691098,-1163065290)+W(6,1022968545,-1100277972,-1106135459,-1113373017)+W(7,1036473238,1042166401,-1109328859,1026417494);sum2=W(0,1041009418,-1106230161,-1113994011,-1100787264)+W(1,-1102450993,-1114680808,1031764893,-1145068408)+W(2,1006794492,1034312638,-1108126219,1060460225)+W(3,-1119222967,-1097084093,-1125377404,-1105852265)+W(4,1023178506,-1120362931,-1105213924,1054015707)+W(5,1053508358,-1133314452,-1141774536,-1120752408)+W(6,-1126244586,1021996758,-1131146954,997147503)+W(7,-1107185372,-1126416406,-1126617106,-1131039214);WS(1044911928,1063248560);
sum1=W(0,-1117210934,1045807559,-1116245664,-1122601008)+W(1,1041679280,-1102494868,1044187563,-1101059428)+W(2,-1089987573,1006551364,-1085623154,-1098705597)+W(3,-1089608778,-1098692501,1040126000,-1100421777)+W(4,1050931427,1049202419,1044690392,1056494849)+W(5,1054654497,1047881833,1043119951,1043071666)+W(6,-1154913199,1049427019,-1098224261,1043742399)+W(7,1009817082,-1102952115,1048685800,-1132265536);sum2=W(0,-1110897864,-1104703066,1039476246,-1102025112)+W(1,1041770976,1044782005,-1112640404,1045848501)+W(2,1031814971,-1126406622,-1112535334,-1088994686)+W(3,1050082866,1038057456,1029663347,-1098794387)+W(4,1060526454,1034850394,1060516426,-1088701567)+W(5,-1072347435,-1075073775,-1077197270,-1081012351)+W(6,-1090228093,-1097166620,-1091926928,1063814816)+W(7,1074296249,1073862535,1067261757,1067785227);WS(-1105546040,1026157880);
sum1=W(0,1040950836,1036866652,1045419231,1057171433)+W(1,1039696013,1040737235,1031337694,1043417390)+W(2,1040614249,1043435937,1048836647,-1092874056)+W(3,1049109967,1037560064,1039556030,1020658754)+W(4,-1102499357,1032157499,-1088963702,-1078642173)+W(5,-1094603626,999044599,-1107844556,-1101965321)+W(6,1036650571,1032871003,1035867609,1040635958)+W(7,1039966133,1035782037,1034875342,1029450491);sum2=W(0,999804672,965076992,1017997216,-1113573416)+W(1,1015814944,1013150208,1004325632,-1116017408)+W(2,1033414560,-1142972544,-1117537424,-1080122522)+W(3,-1116987776,1009041344,1030258512,-1123867424)+W(4,-1131242272,-1152459008,1043660652,1068973644)+W(5,-1113471168,1023678672,-1115573696,1025739248)+W(6,-1111239120,-1114613368,1024438240,1009242816)+W(7,1026341216,-1111376032,-1124670336,1011147520);WS(-1081027239,1060388068);
sum1=W(0,1040945153,1018532824,1048158700,1050078256)+W(1,1043330564,1045983912,1034126717,1042366848)+W(2,1049191505,1052335227,1053224518,-1089652372)+W(3,1050009062,1019623144,1043374892,1037373643)+W(4,-1103567931,-1106690587,-1098210230,-1079677805)+W(5,-1090769236,-1102526621,-1113976903,-1106920486)+W(6,-1142725077,-1126830164,1044049241,1037048166)+W(7,1037549983,-1124021470,1031972104,1000910717);sum2=W(0,1029289565,1023484285,1041097307,1044843621)+W(1,-1101664529,-1108647964,-1111945130,-1129898257)+W(2,-1119356133,1031916514,-1120749829,1057057740)+W(3,1055633817,-1098024997,1038083406,-1101101054)+W(4,-1126159585,-1111485988,-1121314077,1024531885)+W(5,-1102656055,1016983721,-1105960100,1022769465)+W(6,-1119814653,-1133461586,-1112201820,1001931237)+W(7,1035253182,1019582313,1011319026,-1110859200);WS(-1121436896,-1083449266);
sum1=W(0,-1131437006,-1126965659,-1106898372,1049661628)+W(1,-1110051320,1048826500,1018834023,1030351624)+W(2,1057845458,1026072602,1058188821,1047051462)+W(3,1036301673,1049513187,1026266705,1043516478)+W(4,-1096100393,-1106937331,-1089458543,-1093909527)+W(5,-1105302990,-1097831955,-1115312055,-1094725407)+W(6,-1112818966,1025271436,-1120770471,1039868950)+W(7,-1101852248,1048680544,-1111779257,-1137214404);sum2=W(0,1025140224,1016993788,-1106156741,-1085967118)+W(1,-1070014283,-1066270592,-1089828448,-1115300709)+W(2,-1118806788,1030590564,1042721449,1078987048)+W(3,1078555235,1069325982,1051485796,1026006822)+W(4,-1126785121,-1118559458,-1106137914,-1100137345)+W(5,1044823121,-1105174392,-1121082393,1011662011)+W(6,1031495588,991152164,1038491925,1040984057)+W(7,-1111978905,1030579932,-1113499951,-1120641633);WS(1060473294,-1125032523);
sum1=W(0,-1118381578,-1131528546,-1103035725,1044891665)+W(1,1017562024,1038728371,1013193724,1017619335)+W(2,1043924207,1048790648,1057928103,-1096003632)+W(3,-1104437021,-1127678449,-1138265298,1019650740)+W(4,1028842287,-1094915206,1048586166,-1089668066)+W(5,1048997587,-1106021950,1016196772,-1112334062)+W(6,-1103983036,1032416951,-1131359957,1041536420)+W(7,-1119623443,1026802338,-1112764523,1028850580);sum2=W(0,-1124013145,-1154979909,-1113455493,1042673063)+W(1,1009341589,-1131887235,-1126494367,-1120394460)+W(2,1023871771,-1104183315,1024353365,-1099433949)+W(3,1037029004,-1106752952,-1136822537,-1135604889)+W(4,1041717973,-1104961174,-1071159846,1075222357)+W(5,1061754151,-1106459992,1037905746,1020599743)+W(6,1027246941,-1105906795,-1114760758,1048045634)+W(7,-1101645527,1027783079,-1130069351,1023779471);WS(1063175758,1049951270);
sum1=W(0,1051934199,1041620825,1053157077,1019501037)+W(1,-1121035141,1024394007,1034798936,999909159)+W(2,-1084051495,-1091045702,-1089200998,-1103613676)+W(3,-1103906809,1042850683,-1117239270,-1106705027)+W(4,1040719576,1046456792,1054477181,1050464826)+W(5,-1098419444,-1097805325,1011564046,-1091232034)+W(6,1028219745,1028165760,-1110307566,1037889601)+W(7,1045652053,1054554722,1031152711,1056053333);sum2=W(0,-1091471926,1042259987,-1103057728,1049412228)+W(1,1044973062,-1116401558,1011000463,-1130123924)+W(2,1062079447,-1095572989,-1089203271,-1092861102)+W(3,1034556296,1047552828,-1110031497,1051271629)+W(4,1055700238,1041645665,1037140407,-1093629070)+W(5,-1095940003,-1106623325,-1107294450,1053844390)+W(6,1015596856,1033532620,1035045090,1042934527)+W(7,1032040702,-1106239816,1033073048,-1095799213);WS(-1085388366,-1090694979);
sum1=W(0,-1123787314,-1119481145,1032777214,-1112850502)+W(1,1041751591,-1125429276,-1140788444,-1113892940)+W(2,1044273497,-1130943626,1047368143,1059845268)+W(3,-1095680144,1039407200,990533574,1032644049)+W(4,-1108110651,1041576542,-1087220302,1027588771)+W(5,1036323946,-1111657568,1021334836,-1143449895)+W(6,-1115475932,-1117135031,1040347561,-1101064470)+W(7,1037523789,-1126225621,-1134357621,-1109271006);sum2=W(0,-1107190004,1013881877,-1118295314,-1121103222)+W(1,-1127822751,-1115317828,-1126179247,-1114801766)+W(2,1037736456,-1105376838,-1123416196,1042717593)+W(3,-1115549939,1043660085,-1126402007,1040920849)+W(4,-1125693587,1040619572,-1082924015,1068021664)+W(5,1016978358,-1108863865,-1136349779,-1107267301)+W(6,-1120404934,-1122228614,1051908042,-1087341114)+W(7,1042189807,-1125959243,1038966556,1023515477);WS(1065904679,-1122628785);
return clamp(mstd0 + 5.0 * vsum / wsum * mstd1, 0.0, 1.0);
} // nnedi3
vec4 hook() {
vec4 ret = vec4(0.0);
vec4 samples[8];
samples[0][0] = HOOKED_texOff(vec2(-1.0, -3.0)).x;
samples[0][1] = HOOKED_texOff(vec2(-1.0, -2.0)).x;
samples[0][2] = HOOKED_texOff(vec2(-1.0, -1.0)).x;
samples[0][3] = HOOKED_texOff(vec2(-1.0, 0.0)).x;
samples[1][0] = HOOKED_texOff(vec2(-1.0, 1.0)).x;
samples[1][1] = HOOKED_texOff(vec2(-1.0, 2.0)).x;
samples[1][2] = HOOKED_texOff(vec2(-1.0, 3.0)).x;
samples[1][3] = HOOKED_texOff(vec2(-1.0, 4.0)).x;
samples[2][0] = HOOKED_texOff(vec2(0.0, -3.0)).x;
samples[2][1] = HOOKED_texOff(vec2(0.0, -2.0)).x;
samples[2][2] = HOOKED_texOff(vec2(0.0, -1.0)).x;
samples[2][3] = HOOKED_texOff(vec2(0.0, 0.0)).x;
samples[3][0] = HOOKED_texOff(vec2(0.0, 1.0)).x;
samples[3][1] = HOOKED_texOff(vec2(0.0, 2.0)).x;
samples[3][2] = HOOKED_texOff(vec2(0.0, 3.0)).x;
samples[3][3] = HOOKED_texOff(vec2(0.0, 4.0)).x;
samples[4][0] = HOOKED_texOff(vec2(1.0, -3.0)).x;
samples[4][1] = HOOKED_texOff(vec2(1.0, -2.0)).x;
samples[4][2] = HOOKED_texOff(vec2(1.0, -1.0)).x;
samples[4][3] = HOOKED_texOff(vec2(1.0, 0.0)).x;
samples[5][0] = HOOKED_texOff(vec2(1.0, 1.0)).x;
samples[5][1] = HOOKED_texOff(vec2(1.0, 2.0)).x;
samples[5][2] = HOOKED_texOff(vec2(1.0, 3.0)).x;
samples[5][3] = HOOKED_texOff(vec2(1.0, 4.0)).x;
samples[6][0] = HOOKED_texOff(vec2(2.0, -3.0)).x;
samples[6][1] = HOOKED_texOff(vec2(2.0, -2.0)).x;
samples[6][2] = HOOKED_texOff(vec2(2.0, -1.0)).x;
samples[6][3] = HOOKED_texOff(vec2(2.0, 0.0)).x;
samples[7][0] = HOOKED_texOff(vec2(2.0, 1.0)).x;
samples[7][1] = HOOKED_texOff(vec2(2.0, 2.0)).x;
samples[7][2] = HOOKED_texOff(vec2(2.0, 3.0)).x;
samples[7][3] = HOOKED_texOff(vec2(2.0, 4.0)).x;
ret[0] = nnedi3(samples);
return ret;
} // hook
//!DESC NNEDI3 (combine_x, nns128, win8x4)
//!HOOK LUMA
//!BIND HOOKED
//!BIND nnedi3_int
//!WIDTH 2 HOOKED.w *
//!OFFSET -0.500000 0.000000
//!WHEN HOOKED.w OUTPUT.w / 0.707106 <
vec4 hook() {
vec2 dir = fract(HOOKED_pos * HOOKED_size) - 0.5;
if (dir.x < 0.0) {
return HOOKED_texOff(-dir);
} else {
return nnedi3_int_texOff(-dir);
}
}