mirror of
https://github.com/ksyasuda/aniwrapper.git
synced 2025-07-03 01:03:32 -07:00
Compare commits
137 Commits
d8b5f2b94a
...
master
Author | SHA1 | Date | |
---|---|---|---|
211850c85f | |||
06d3ad3ff2 | |||
3117738f27 | |||
64d70c34f2 | |||
d9d7549553 | |||
5804f84f83 | |||
fd954e7ede | |||
da45bf15fe | |||
b3f1dea8ab | |||
2c7789c58f | |||
2bab68a887 | |||
df82425eae | |||
b92dd11fe6 | |||
c384c93147 | |||
fa108d860f | |||
1c8afc16cc | |||
e8054c6cf2 | |||
bd949bb7c7 | |||
737d54bcd2 | |||
7d574f7a6f | |||
7ad12b0da8 | |||
c7911dc0a7 | |||
92b10cc0f6 | |||
e9c2048076 | |||
acdcf05514 | |||
ec41f5abb3 | |||
af7dee7d85 | |||
822e40074c | |||
80682a26db | |||
4828923abb | |||
ba6c302022 | |||
f218b34e21 | |||
e5772469c7 | |||
2e53ac3bfc | |||
8d6acddea6 | |||
870920cbf5 | |||
1b797bee3e | |||
692301d893 | |||
77eaa9e4b0 | |||
ce83a6155b | |||
73e6b8d181 | |||
6dd2b4c279 | |||
04476f3ba4 | |||
d061438e2e | |||
505e5125b9 | |||
9322d028f8 | |||
0892bb1845 | |||
ae0c19b5f2 | |||
13635cabf2 | |||
d7e78836a4 | |||
7c8a13573b | |||
2f0f552068 | |||
47f9ca19ae | |||
acb236ce23 | |||
fd59f7e2fe | |||
925b7c86e2 | |||
aa821e774a | |||
73eb2a274e | |||
6af4a46b86 | |||
cee96ec9cc | |||
1d1dc517f4 | |||
0ea84fb450 | |||
8327afc43e | |||
c7fb101b10 | |||
228c2014c7 | |||
006fdc6572 | |||
3c4189e3ac | |||
5c7093daf0 | |||
776c4961aa | |||
aac3761e37 | |||
aa39625956 | |||
4af41db0bf | |||
8882405c0e | |||
4d704d4b32 | |||
7a3a61bb58 | |||
f95ae51af8 | |||
8fb570b003 | |||
d7bd5899b5 | |||
924b0eed76 | |||
74ac27bb79 | |||
7c85a91d65 | |||
e851b92289 | |||
04cad2425b | |||
d390d0a683 | |||
3bfbaa7749 | |||
6137deb26b | |||
a56fe29a29 | |||
f23586116d | |||
6e5b3c463a | |||
01fe1bb68a | |||
02349915c1 | |||
1461c3bc62 | |||
4c2d7ae27e | |||
d2611e6e33 | |||
41c40bbd38 | |||
90dec870e0 | |||
e29d3f7db3 | |||
7907e809b8 | |||
7a0eea5d69 | |||
f1fbb643aa | |||
8895ab9145 | |||
9f80566b6e | |||
024bb138f0 | |||
3b5511cfb4 | |||
3647be366f | |||
260d212e22 | |||
cc9d66d4a2 | |||
eb0677fef3 | |||
2221d550c0 | |||
86a4e187a6 | |||
fa958884bb | |||
b272fc3994 | |||
c6d5c6a1bd | |||
593b66edea | |||
cdfe2674d7 | |||
7d08c212fa | |||
10a675202a | |||
c3b0a26ce7 | |||
49cf4f3ecc | |||
86acb7d731 | |||
1268855077 | |||
087fb9d355 | |||
42db51371b | |||
5c7af5c36d | |||
cf7cf4b591 | |||
1fddd452fe | |||
5aad3a7263 | |||
a6e80c1ad0 | |||
c5bf198466 | |||
1a54bf3b44 | |||
0d97d3857a | |||
280bd73760 | |||
c18cb37f71 | |||
9cb0075cd1 | |||
0ba2ebac2c | |||
2d7ed5dce0 | |||
14dee88f11 |
BIN
.assets/showcase.jpg
Normal file
BIN
.assets/showcase.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 205 KiB |
10
Makefile
10
Makefile
@ -3,10 +3,12 @@ PREFIX := /usr
|
||||
all: install
|
||||
|
||||
install: uninstall
|
||||
cp ani-cli $(DESTDIR)$(PREFIX)/bin/ani-cli
|
||||
cp aniwrapper $(DESTDIR)$(PREFIX)/bin/aniwrapper
|
||||
chmod 0755 $(DESTDIR)$(PREFIX)/bin/ani-cli
|
||||
chmod 0755 $(DESTDIR)$(PREFIX)/bin/aniwrapper
|
||||
install -m0755 ani-cli $(DESTDIR)$(PREFIX)/bin/ani-cli
|
||||
install -m0755 aniwrapper $(DESTDIR)$(PREFIX)/bin/aniwrapper
|
||||
mkdir -p /usr/local/man/man1
|
||||
install -m0644 docs/man/aniwrapper.1 /usr/local/man/man1/
|
||||
gzip -qf /usr/local/man/man1/aniwrapper.1
|
||||
mandb -q
|
||||
|
||||
dev: uninstall
|
||||
ln -sr ./ani-cli $(DESTDIR)$(PREFIX)/bin/ani-cli
|
||||
|
271
README.md
271
README.md
@ -4,7 +4,7 @@
|
||||
|
||||
[**_Setup_**](#setup) | [**_Usage_**](#usage) | [**_Screenshots_**](#screenshots)
|
||||
|
||||

|
||||
[](https://user-images.githubusercontent.com/33813108/153382027-f77c8219-af79-4a06-91b2-466cc7e2157a.mp4)
|
||||
|
||||
</div>
|
||||
|
||||
@ -29,40 +29,27 @@ This tool scrapes the site [gogoanime](https://gogoanime.cm).
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Setup](#setup)
|
||||
- [Skip Intro Script](#skip-intro-script)
|
||||
- [Installing](#installing)
|
||||
- [Arch Linux](#arch-linux)
|
||||
- [Manual Install](#manual-install)
|
||||
- [Run the setup and install the script](#run-the-setup-and-install-the-script)
|
||||
- [Aniwrapper Menus](#aniwrapper-menus)
|
||||
- [Search Anime](#search-anime)
|
||||
- [Dealing with conflicting search queries / rofi grabbing from search list](#dealing-with-conflicting-search-queries--rofi-grabbing-from-search-list)
|
||||
- [Anime Selection](#anime-selection)
|
||||
- [Episode Selection](#episode-selection)
|
||||
- [Usage](#usage)
|
||||
- [aniwrapper](#aniwrapper-1)
|
||||
- [Option 1: Streaming](#option-1-streaming)
|
||||
- [Option 2: Download](#option-2-download)
|
||||
- [Option 3: Continue](#option-3-continue)
|
||||
- [Option 4: Play from File](#option-4-play-from-file)
|
||||
- [Option 5: Sync History](#option-5-sync-history)
|
||||
- [Option 6: Choose Theme](#option-6-choose-theme)
|
||||
- [ani-cli](#ani-cli)
|
||||
- [Screenshots](#screenshots)
|
||||
- [Aniwrapper](#aniwrapper)
|
||||
- [Introduction](#introduction)
|
||||
- [MPV Extension - Skip Intro Script](#mpv-extension---skip-intro-script)
|
||||
- [Installing](#installing)
|
||||
- [Manual Install](#manual-install)
|
||||
- [Aniwrapper Menus](#aniwrapper-menus)
|
||||
- [Dealing with conflicting search queries / rofi grabbing from search list](#dealing-with-conflicting-search-queries--rofi-grabbing-from-search-list)
|
||||
- [Usage](#usage)
|
||||
- [aniwrapper](#aniwrapper-1)
|
||||
- [Option 1: Streaming](#option-1-streaming)
|
||||
- [Option 2: Download](#option-2-download)
|
||||
- [Option 3: Continue](#option-3-continue)
|
||||
- [Option 4: Play from File](#option-4-play-from-file)
|
||||
- [Option 5: Sync History](#option-5-sync-history)
|
||||
- [Option 6: Choose Theme](#option-6-choose-theme)
|
||||
- [ani-cli](#ani-cli)
|
||||
- [Themes](#themes)
|
||||
|
||||
<!-- markdown-toc end -->
|
||||
|
||||
# Setup
|
||||
|
||||
These are the minimum dependences required to run `aniwrapper`
|
||||
|
||||
```
|
||||
aria2 curl grep mpv rofi sed sqlite3
|
||||
```
|
||||
|
||||
## Skip Intro Script
|
||||
# MPV Extension - Skip Intro Script
|
||||
|
||||
_This repo comes packaged with and will install the
|
||||
[skip-intro.lua](https://github.com/rui-ddc/skip-intro)
|
||||
@ -73,17 +60,23 @@ script for MPV during setup if it is not already installed_
|
||||
Upon activation, the skip-intro script will try its best to skip the
|
||||
episode introduction by skipping to the next moment of silence in the video
|
||||
|
||||
- If the video has not pre-loaded past the introduction, the script will not
|
||||
know what to do. Press `TAB` again to stop the script until the video
|
||||
has loaded enough, or just manually skip past the intro.
|
||||
- If the video does not have a pause in audio (or a significant enough drop in
|
||||
audio volume) between the end of the introduction and the beginning of the
|
||||
video/episode, then the script may fail and skip to a random point in the
|
||||
video
|
||||
- If the video has not pre-loaded past the introduction, the script will not
|
||||
know what to do. Press `TAB` again to stop the script until the video
|
||||
has loaded enough, or just manually skip past the intro.
|
||||
- If the video does not have a pause in audio (or a significant enough drop in
|
||||
audio volume) between the end of the introduction and the beginning of the
|
||||
video/episode, then the script may fail and skip to a random point in the
|
||||
video
|
||||
|
||||
## Installing
|
||||
# Installing
|
||||
|
||||
### Arch Linux
|
||||
These are the minimum dependences required to run `aniwrapper`
|
||||
|
||||
```
|
||||
axel curl ffmpeg grep mpv rofi sed sqlite3
|
||||
```
|
||||
|
||||
**Arch Linux**
|
||||
|
||||
`aniwrapper-git` is available on the [AUR](https://aur.archlinux.org/packages/aniwrapper-git/) for Arch users
|
||||
|
||||
@ -93,16 +86,16 @@ or
|
||||
yay -S aniwrapper-git
|
||||
```
|
||||
|
||||
### Manual Install
|
||||
## Manual Install
|
||||
|
||||
Install the Dependencies
|
||||
|
||||
```sh
|
||||
# Arch
|
||||
pacman -S --needed aria2 curl grep mpv rofi sed sqlite3
|
||||
pacman -S --needed axel curl ffmpeg grep mpv rofi sed sqlite3
|
||||
|
||||
# Debian
|
||||
apt install aria2 curl grep mpv rofi sed sqlite3
|
||||
apt install axel curl ffmpeg grep mpv rofi sed sqlite3
|
||||
```
|
||||
|
||||
Clone and switch into the repo directory
|
||||
@ -111,9 +104,7 @@ Clone and switch into the repo directory
|
||||
git clone https://github.com/ksyasuda/aniwrapper && cd aniwrapper
|
||||
```
|
||||
|
||||
#### Run the setup and install the script
|
||||
|
||||
From the `aniwrapper` directory, run the following commands to set up and install the script
|
||||
Then, from the `aniwrapper` directory, run the following commands to set up and install the script
|
||||
|
||||
```sh
|
||||
chmod +x setup.sh
|
||||
@ -122,15 +113,9 @@ chmod +x setup.sh
|
||||
|
||||
# Aniwrapper Menus
|
||||
|
||||
There are several menus used to drive the program forward
|
||||
See [aniwrapper menus](docs/aniwrapper-menus.md)
|
||||
|
||||
## Search Anime
|
||||
|
||||
The first menu consists of a search box and a list of anime titles corresponding to past valid searches. Choose an option from the menu, or enter in a unique search query to search for a new anime. The result from this will be used to query against `gogoanime` and return similar named anime
|
||||
|
||||
If selecting an anime from the provided list, the [anime selection](#anime-selection) menu will be skipped and the program will move on to [episode selection](#episode-selection) for the chosen anime
|
||||
|
||||
### Dealing with conflicting search queries / rofi grabbing from search list
|
||||
# Dealing with conflicting search queries / rofi grabbing from search list
|
||||
|
||||
In this program, rofi is configured to search with case insensitivity and select the best match from the list if there are matches. This can make it difficult at times to write a search query that does not trigger a selection from the rofi menu
|
||||
|
||||
@ -140,72 +125,44 @@ In this program, rofi is configured to search with case insensitivity and select
|
||||
Once your history starts filling up, it becomes progressively more difficult to form unique search queries
|
||||
|
||||

|
||||
The workaround for this is to append a dash ` -` to the end of the search query<br/>
|
||||
A workaround for this is to append a dash `-` to the end of the search query<br/>
|
||||
The above output was produced by searching: `isekai -`
|
||||
|
||||
</div>
|
||||
|
||||
## Anime Selection
|
||||
|
||||
The next menu is where you select the anime to watch from a narrowed down list of candidates. Titles that are highlighed in blue indicate that anime has been selected before
|
||||
|
||||
## Episode Selection
|
||||
|
||||
> Half-episodes (ex. saihate-no-paladin episode 7.5) are selectable, however they will not show up in the episodes list.
|
||||
> To select half episodes add 'h' to the beginning for episodes like '7.5' -> 'h7' to select saihate-no-paladin episode 7.5
|
||||
|
||||
Here you will be prompted to select the episode(s) to watch/download
|
||||
|
||||
Multiple episodes can be downloaded by giving the episode range like so
|
||||
|
||||
```
|
||||
Select Episode [1-13]: 1 6
|
||||
```
|
||||
|
||||
This would open/download episodes 1 2 3 4 5 6
|
||||
|
||||
# Usage
|
||||
|
||||
## aniwrapper
|
||||
|
||||
```
|
||||
# Launch menu (default video quality: best)
|
||||
aniwrapper
|
||||
|
||||
# Launch menu with quality selection
|
||||
aniwrapper -q
|
||||
|
||||
# Enable verbose logging
|
||||
aniwrapper -v
|
||||
|
||||
# Connect to history database
|
||||
aniwrapper [-cdhpqSv] [-t <theme> or -T <config_path>] <query>
|
||||
aniwrapper [-cpqSv] [-t <theme> or -T <config_path>] -f <path_to_directory>
|
||||
aniwrapper -Q <query>
|
||||
aniwrapper -C
|
||||
|
||||
# Enable silent mode (suppress output to stdout) [cannot be used with -v]
|
||||
aniwrapper -S
|
||||
|
||||
# Query the history database
|
||||
aniwrapper -Q <query>
|
||||
|
||||
# Choose rofi theme from presets
|
||||
aniwrapper -t <aniwrapper (default)|dracula|doomone|fancy|flamingo|material|nord|onedark>
|
||||
|
||||
# Specify custom rofi config
|
||||
aniwrapper -T <path_to_config>
|
||||
|
||||
# Specify starting directory for play_from_file mode, bypassing main menu
|
||||
aniwrapper -f <starting_directory>
|
||||
|
||||
# Use ani-cli command-line mode (rofi disabled)
|
||||
aniwrapper -c
|
||||
|
||||
# Download anime in command-line mode
|
||||
aniwrapper -d
|
||||
aniwrapper <query> # Run in stream mode, searching for <query>
|
||||
aniwrapper -c # Use ani-cli command-line mode (rofi disabled)
|
||||
aniwrapper -C # Connect to history database
|
||||
aniwrapper -d # Download anime in command-line mode
|
||||
aniwrapper -d <query> # Run in download mode (best quality), searching for <query>
|
||||
aniwrapper -e <episode> or <begin_episode - end_episode>
|
||||
aniwrapper -f <starting_directory> # Specify starting directory for play_from_file mode, bypassing main menu
|
||||
aniwrapper -h # Show help menu
|
||||
aniwrapper -p # Enable player selection menu
|
||||
aniwrapper -q # Launch menu with quality selection
|
||||
aniwrapper -Q <query> # Query the history database
|
||||
aniwrapper -r # Launch aniwrapper in quick-resume mode (start script on episode selection for the most recently streamed anime)
|
||||
aniwrapper -S # Enable silent mode (suppress output to stdout) [cannot be used with -v]
|
||||
aniwrapper -t <theme> # Choose rofi theme from presets
|
||||
aniwrapper -T <path_to_config> # Specify custom rofi config
|
||||
aniwrapper -v # Enable verbose logging
|
||||
```
|
||||
|
||||
See [aniwrapper menus](docs/aniwrapper-menus.md) for more information about the menus used in the following options
|
||||
|
||||
### Option 1: Streaming
|
||||
|
||||
Streaming is the default option for the `aniwrapper` script and will prompt you with each of the menus specified in the _[aniwrapper Menus](#aniwrapper-menus)_ section
|
||||
Streaming is the default option for the `aniwrapper` script
|
||||
|
||||
<details>
|
||||
|
||||
@ -223,15 +180,50 @@ Streaming is the default option for the `aniwrapper` script and will prompt you
|
||||
|
||||
The default download location is `$HOME/Videos/sauce` and will be chosen as the download directory unless otherwise specified
|
||||
|
||||
After specifying the download directory (or leaving it blank for the default), you will be presented with the menus from the _[aniwrapper Menus](#aniwrapper-menus)_ section for selecting the anime and episode(s) to download
|
||||
<details>
|
||||
|
||||
<summary>Example</summary>
|
||||
|
||||
<div align="center">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
</details>
|
||||
|
||||
### Option 3: Continue
|
||||
|
||||
The continue option queries the `sqlite3` history databse and pulls the list of distinct anime names from the `watch_history` table. Select an option from the list and the most recently watched episode of the selected anime will play
|
||||
|
||||
### Option 4: Play from File
|
||||
<details>
|
||||
|
||||
This option prompts you to provide the path to your `Videos` directory. Any path can be provided, but the script will begin the search from the provided path. From there, follow the prompts to select the video you want to watch and it will be opened in `mpv`
|
||||
<summary>Example</summary>
|
||||
|
||||
<div align="center">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
</details>
|
||||
|
||||
### Option 4: Recently Updated Anime
|
||||
|
||||
This option will present the name and episode number of 30 recently updated anime on gogoanime
|
||||
|
||||
<details>
|
||||
<summary>Example</summary>
|
||||
|
||||
<div align="center">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
</details>
|
||||
|
||||
### Option 5: Play from File
|
||||
|
||||
<details>
|
||||
|
||||
@ -245,19 +237,19 @@ This option prompts you to provide the path to your `Videos` directory. Any path
|
||||
|
||||
</details>
|
||||
|
||||
### Option 5: Sync History
|
||||
### Option 6: Sync History
|
||||
|
||||
This option allows you to sync your search/watch history across devices. It queries the database on the remote machine and inserts/updates the necessary rows
|
||||
|
||||
At the moment, the requirements are as follows:
|
||||
|
||||
- You must be able to `ssh` into the remote machine
|
||||
- The username must be the same across both devices
|
||||
- The `history.sqlite3` file must be in the default location: `$XDG_CONFIG_HOME/aniwrapper/history.sqlite3`
|
||||
- You must be able to `ssh` into the remote machine
|
||||
- The username must be the same across both devices
|
||||
- The `history.sqlite3` file must be in the default location: `$XDG_CONFIG_HOME/aniwrapper/history.sqlite3`
|
||||
|
||||
### Option 6: Choose Theme
|
||||
### Option 7: Choose Theme
|
||||
|
||||
Allows for changing the aniwrapper theme from the main menu
|
||||
Change aniwrapper theme
|
||||
|
||||
<details>
|
||||
|
||||
@ -271,49 +263,20 @@ Allows for changing the aniwrapper theme from the main menu
|
||||
|
||||
</details>
|
||||
|
||||
## ani-cli
|
||||
|
||||
```
|
||||
# watch anime
|
||||
ani-cli <query>
|
||||
|
||||
# verbose logging
|
||||
ani-cli -v
|
||||
|
||||
# download anime
|
||||
ani-cli -d <download_directory>
|
||||
|
||||
# resume watching anime
|
||||
ani-cli -H
|
||||
|
||||
# sync history across devices
|
||||
ani-cli -s
|
||||
|
||||
# choose quality
|
||||
ani-cli -q <best (default)|1080p|720p|480p|360p|worst>
|
||||
|
||||
# choose rofi theme from presets
|
||||
ani-cli -t <aniwrapper (default)|dracula|fancy|flamingo|material|nord|onedark>
|
||||
|
||||
# Specify starting directory for play_from_file mode (does not work with -c)
|
||||
ani-cli -f <starting_directory>
|
||||
|
||||
# run ani-cli in command-line mode (rofi disabled)
|
||||
ani-cli -c
|
||||
```
|
||||
|
||||
# Screenshots
|
||||
# Themes
|
||||
|
||||
<div align="center">
|
||||
|
||||
Main Menu (default theme)
|
||||
Default theme
|
||||
|
||||

|
||||

|
||||
|
||||
| | |
|
||||
| :---------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------: |
|
||||
| <details><summary>doom-one</summary>  </details> | <details><summary>dracula</summary> </details> |
|
||||
| <details><summary>fancy</summary></details> | <details><summary>material</summary></details> |
|
||||
| <details><summary>onedark</summary></details> | <details><summary>flamingo (sidebar theme)</summary></details> |
|
||||
| | |
|
||||
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
||||
| <details><summary>alter</summary>  </details> | <details><summary>aniwrapper</summary>  </details> |
|
||||
| <details><summary>doom-one</summary>  </details> | <details><summary>dracula</summary> </details> |
|
||||
| <details><summary>fancy</summary></details> | <details><summary>material</summary></details> |
|
||||
| <details><summary>monokai</summary></details> | <details><summary>nord</summary></details> |
|
||||
| <details><summary>nord2</summary></details> | <details><summary>onedark</summary></details> |
|
||||
|
||||
</div>
|
||||
|
449
aniwrapper
449
aniwrapper
@ -2,64 +2,81 @@
|
||||
|
||||
set -Eeo pipefail
|
||||
|
||||
#############
|
||||
# Globals #
|
||||
#############
|
||||
CMD="/usr/bin/ani-cli"
|
||||
CFG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/aniwrapper"
|
||||
CFG_FILE="$CFG_DIR/themes/aniwrapper.rasi"
|
||||
DEFAULT_DOWNLOAD="$HOME/Videos/sauce"
|
||||
ROFI_THEME="aniwrapper.rasi"
|
||||
THEMES="aniwrapper (default)|dracula|doomone|fancy|flamingo|material|nord|onedark"
|
||||
QUALITIES="1. best|2. 1080p|3. 720p|4. 360p|5. worst"
|
||||
THEMES="alter|aniwrapper|dracula|doomone|fancy|material|monokai|nord|nord2|onedark"
|
||||
QUALITIES="1. best|2. worst"
|
||||
SUPPORTED_PLAYERS="mpv|vlc"
|
||||
QUALITY=best
|
||||
PLAYER_FN=mpv
|
||||
DPI=96
|
||||
IS_AUTOPLAY=0
|
||||
GET_QUALITY=0
|
||||
IS_CUSTOM_THEME=0
|
||||
IS_DOWNLOAD=0
|
||||
IS_PLAY_FROM_FILE=0
|
||||
IS_ROFI=1
|
||||
VERBOSE=0
|
||||
IS_SYNC=0
|
||||
IS_ALTERNATE_PLAYER=0
|
||||
IS_VERBOSE=0
|
||||
IS_SELECT_EPISODE=1
|
||||
SELECT_PROVIDER=0
|
||||
SILENT=0
|
||||
|
||||
quit="7. Quit"
|
||||
options="1. Stream|2. Download|3. Continue|4. Play from File|5. Sync History|6. Choose Theme|$quit"
|
||||
quit="8. Quit"
|
||||
options="1. Stream|2. Download|3. Continue|4. Recently Updated|5. Play from File|6. Sync History|7. Choose Theme|$quit"
|
||||
theme=default
|
||||
|
||||
#############
|
||||
# Functions #
|
||||
#############
|
||||
help_text() {
|
||||
while IFS= read -r line; do
|
||||
printf "%s\n" "$line"
|
||||
done <<< "
|
||||
Usage:
|
||||
aniwrapper [-cdhvqS] [-t <theme> or -T <config_path>]
|
||||
aniwrapper [-cvS] [-t <theme> or -T <config_path>] -f <path_to_directory>
|
||||
aniwrapper -Q <query>
|
||||
aniwrapper -C
|
||||
aniwrapper [-adehpqSv] [-t <theme> | -T <config_path>] [<query>]
|
||||
aniwrapper -f <directory_path> [-t <theme> | -T <config_path>] [-pSv] [<query>]\
|
||||
aniwrapper -c [-dehpqSv] [<query>]
|
||||
aniwrapper -Q <query>
|
||||
aniwrapper -C
|
||||
Options:
|
||||
-h show this help text
|
||||
-q enable quality selection
|
||||
-c enable command-line mode (rofi disabled)
|
||||
-d download episode in command-line mode
|
||||
-C connect to history database
|
||||
-S silent mode (suppress output to stdout) [cannot be used with -v]
|
||||
|
||||
-t <aniwrapper (default)|dracula|doomone|fancy|flamingo|material|onedark> change rofi theme
|
||||
-T <config_path> specify custom rofi theme
|
||||
-f <path_to_directory> (no trailing slash) specify starting directory for play for file mode
|
||||
-Q <query> query the history database
|
||||
-a enable autoplay
|
||||
-c enable command-line mode (rofi disabled)
|
||||
-C connect to history database
|
||||
-d download episode in command-line mode
|
||||
-e [<episode> | <begin> - <end>] select episode(s) to stream/download
|
||||
-f <path_to_directory> (no trailing slash) specify starting directory for play for file mode
|
||||
-h show this help text
|
||||
-p enable player selection menu
|
||||
-P select provider to scrape first
|
||||
-q enable quality selection
|
||||
-Q <query> query the history database
|
||||
-r start script in episode selection using the most recently watched anime
|
||||
-v verbose output
|
||||
-S silent mode (suppress output to stdout) [cannot be used with -v]
|
||||
-t <alter|aniwrapper (default)|dracula|doomone|fancy|material|monokai|nord|nord2|onedark> change rofi theme
|
||||
-T <config_path> specify custom rofi theme
|
||||
"
|
||||
}
|
||||
|
||||
lg() {
|
||||
if ((VERBOSE == 1)); then
|
||||
printf "%s\n" "$*"
|
||||
if ((IS_VERBOSE)); then
|
||||
inf "$*"
|
||||
fi
|
||||
}
|
||||
|
||||
seppuku() {
|
||||
# display an informational message (first argument in green, second in magenta)
|
||||
inf() {
|
||||
printf "\033[1;32m%s \033[1;35m%s\033[0m\n" "$1" "$2"
|
||||
}
|
||||
|
||||
# prompts the user with message in $1-2 ($1 in blue, $2 in magenta) and saves the input to the variables in $REPLY and $REPLY2
|
||||
prompt() {
|
||||
printf "\033[1;34m%s\033[1;35m%s\033[1;34m: \033[0m" "$1" "$2"
|
||||
}
|
||||
|
||||
die() {
|
||||
printf "%s\n" "$*"
|
||||
exit 1
|
||||
}
|
||||
@ -70,50 +87,52 @@ quit() {
|
||||
}
|
||||
|
||||
run() {
|
||||
if ((IS_PLAY_FROM_FILE == 0 && GET_QUALITY == 1)); then
|
||||
get_quality
|
||||
fi
|
||||
if ((SILENT == 1)); then
|
||||
if ((IS_CUSTOM_THEME == 0)); then
|
||||
"$CMD" -D"$DPI" -Sq "$QUALITY" -t "$theme" "$@"
|
||||
else
|
||||
"$CMD" -D"$DPI" -Sq "$QUALITY" -T "$CFG_FILE" "$@"
|
||||
fi
|
||||
elif ((VERBOSE == 1)); then
|
||||
if ((IS_CUSTOM_THEME == 0)); then
|
||||
"$CMD" -D"$DPI" -vq "$QUALITY" -t "$theme" "$@"
|
||||
else
|
||||
"$CMD" -D"$DPI" -vq "$QUALITY" -T "$CFG_FILE" "$@"
|
||||
fi
|
||||
else
|
||||
if ((IS_CUSTOM_THEME == 0)); then
|
||||
"$CMD" -D"$DPI" -q "$QUALITY" -t "$theme" "$@"
|
||||
else
|
||||
"$CMD" -D"$DPI" -q "$QUALITY" -T "$CFG_FILE" "$@"
|
||||
fi
|
||||
if ((IS_CUSTOM_THEME)); then
|
||||
args+=(-T"$CFG_FILE")
|
||||
elif ((!IS_CUSTOM_THEME)); then
|
||||
args+=(-t"$theme")
|
||||
fi
|
||||
lg "Running $CMD ${args[*]} -D$DPI $*"
|
||||
$CMD "${args[@]}" -D"$DPI" "$@"
|
||||
}
|
||||
|
||||
get_quality() {
|
||||
if ((IS_ROFI == 1)); then
|
||||
if ((IS_ROFI)); then
|
||||
selection=$(rofi -dpi "$DPI" -dmenu -config "$CFG_FILE" \
|
||||
-l 5 -selected-row 0 -a 0 \
|
||||
-theme-str 'listview {columns: 1;}' -p "Choose video quality:" \
|
||||
-sep '|' -only-match <<< "$QUALITIES")
|
||||
-l 6 -selected-row 0 -a 0 -window-title 'aniwrapper' \
|
||||
-theme-str 'listview {columns: 1;} window {width: 25%;}' \
|
||||
-p "Choose video quality:" \
|
||||
-sep '|' -no-custom <<< "$QUALITIES")
|
||||
QUALITY=$(awk '{print $2}' <<< "$selection")
|
||||
else
|
||||
qualities="best|1080p|720p|480p|360p|worst"
|
||||
printf "%s" "Choose quality: [$qualities]: "
|
||||
qualities="best|worst"
|
||||
prompt "Choose quality " "[$qualities]"
|
||||
read -r QUALITY
|
||||
while [[ ! "$QUALITY" =~ ($qualities) ]]; do
|
||||
lg "$QUALITY not a valid quality -> [$qualities]"
|
||||
printf "%s" "Choose quality: [$qualities]: "
|
||||
prompt "Choose quality " "[$qualities]"
|
||||
read -r QUALITY
|
||||
done
|
||||
fi
|
||||
lg "selected quality: $QUALITY"
|
||||
}
|
||||
|
||||
# return the index in $THEMES of $ROFI_THEME
|
||||
get_theme_idx() {
|
||||
themeslist="aniwrapper-alter.rasi|aniwrapper.rasi|aniwrapper-dracula.rasi|aniwrapper-doomone.rasi|aniwrapper-fancy.rasi|aniwrapper-material.rasi|aniwrapper-monokai.rasi|aniwrapper-nord.rasi|aniwrapper-nord2.rasi|aniwrapper-onedark.rasi"
|
||||
idx=0
|
||||
while IFS='|' read -ra themes; do
|
||||
for t in "${themes[@]}"; do
|
||||
if [[ "$t" == "$ROFI_THEME" ]]; then
|
||||
lg "theme -> $t | theme index -> $idx" > /dev/stderr
|
||||
printf "%s\n" "$idx"
|
||||
break
|
||||
fi
|
||||
((++idx))
|
||||
done
|
||||
done <<< "$themeslist"
|
||||
}
|
||||
|
||||
# generates a span mesg for rofi given
|
||||
# input: message: str
|
||||
generate_span() {
|
||||
@ -128,29 +147,8 @@ set_theme() {
|
||||
aniwrapper)
|
||||
ROFI_THEME=aniwrapper.rasi
|
||||
;;
|
||||
dracula)
|
||||
ROFI_THEME=aniwrapper-dracula.rasi
|
||||
;;
|
||||
doomone | doom-one)
|
||||
ROFI_THEME=aniwrapper-doomone.rasi
|
||||
;;
|
||||
fancy)
|
||||
ROFI_THEME=aniwrapper-fancy.rasi
|
||||
;;
|
||||
flamingo)
|
||||
ROFI_THEME=aniwrapper-flamingo.rasi
|
||||
;;
|
||||
material)
|
||||
ROFI_THEME=aniwrapper-material.rasi
|
||||
;;
|
||||
nord)
|
||||
ROFI_THEME=aniwrapper-nord.rasi
|
||||
;;
|
||||
onedark)
|
||||
ROFI_THEME=aniwrapper-onedark.rasi
|
||||
;;
|
||||
*)
|
||||
seppuku "$theme not a valid theme file. Themes: [$THEMES]"
|
||||
ROFI_THEME="aniwrapper-$new_theme.rasi"
|
||||
;;
|
||||
esac
|
||||
lg "Chosen theme -> $ROFI_THEME"
|
||||
@ -158,41 +156,51 @@ set_theme() {
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
while getopts 'vhqcdf:-:t:T:CQ:D:S' OPT; do
|
||||
while getopts 'acCdD:e:f:hpPqQ:rSt:T:v' OPT; do
|
||||
case "$OPT" in
|
||||
h)
|
||||
help_text
|
||||
exit 0
|
||||
;;
|
||||
v)
|
||||
VERBOSE=1
|
||||
;;
|
||||
q)
|
||||
GET_QUALITY=1
|
||||
lg "Quality prompt enabled"
|
||||
a)
|
||||
IS_AUTOPLAY=1
|
||||
;;
|
||||
c)
|
||||
IS_ROFI=0
|
||||
lg "Command-line (ani-cli) mode set"
|
||||
;;
|
||||
C)
|
||||
lg "Connecting to history database -> $CFG_DIR/history.sqlite3"
|
||||
sqlite3 "$CFG_DIR/history.sqlite3"
|
||||
exit $?
|
||||
;;
|
||||
d)
|
||||
IS_DOWNLOAD=1
|
||||
lg "Download flag set..."
|
||||
;;
|
||||
D)
|
||||
DPI="$OPTARG"
|
||||
;;
|
||||
e)
|
||||
episodes="$OPTARG"
|
||||
[[ "$episodes" =~ ^[0-9]+(-[0-9]+)? ]] || die "Invalid episode range: $episodes"
|
||||
IS_SELECT_EPISODE=0
|
||||
;;
|
||||
f)
|
||||
IS_PLAY_FROM_FILE=1
|
||||
play_path="$OPTARG"
|
||||
lg "Play from file flag set... skipping main menu"
|
||||
lg "PLAY_PATH: $play_path"
|
||||
;;
|
||||
t)
|
||||
theme="$OPTARG"
|
||||
set_theme "$theme"
|
||||
h)
|
||||
help_text
|
||||
exit 0
|
||||
;;
|
||||
C)
|
||||
lg "Connecting to history database -> $CFG_DIR/history.sqlite3"
|
||||
sqlite3 "$CFG_DIR/history.sqlite3"
|
||||
exit $?
|
||||
p)
|
||||
IS_ALTERNATE_PLAYER=1
|
||||
;;
|
||||
P)
|
||||
SELECT_PROVIDER=1
|
||||
;;
|
||||
q)
|
||||
GET_QUALITY=1
|
||||
lg "Quality prompt enabled"
|
||||
;;
|
||||
Q)
|
||||
query="$OPTARG"
|
||||
@ -200,17 +208,25 @@ parse_args() {
|
||||
sqlite3 -line "$CFG_DIR/history.sqlite3" "$query"
|
||||
exit $?
|
||||
;;
|
||||
T)
|
||||
CFG_FILE="$OPTARG"
|
||||
[ ! -f "$CFG_FILE" ] && seppuku "config file $CFG_FILE does not exist"
|
||||
IS_CUSTOM_THEME=1
|
||||
;;
|
||||
D)
|
||||
DPI="$OPTARG"
|
||||
r)
|
||||
IS_RESUME=1
|
||||
lg "Selecting previously watched anime"
|
||||
;;
|
||||
S)
|
||||
SILENT=1
|
||||
;;
|
||||
t)
|
||||
theme="$OPTARG"
|
||||
set_theme "$theme"
|
||||
;;
|
||||
T)
|
||||
CFG_FILE="$OPTARG"
|
||||
[ ! -f "$CFG_FILE" ] && die "config file $CFG_FILE does not exist"
|
||||
IS_CUSTOM_THEME=1
|
||||
;;
|
||||
v)
|
||||
IS_VERBOSE=1
|
||||
;;
|
||||
*)
|
||||
help_text
|
||||
exit 1
|
||||
@ -219,28 +235,127 @@ parse_args() {
|
||||
done
|
||||
}
|
||||
|
||||
check_flags() {
|
||||
# Check if command-line flag is set
|
||||
if ((VERBOSE == 1 && SILENT == 1)); then
|
||||
seppuku "verbose and silent options cannot be used together"
|
||||
get_player() {
|
||||
msg1="Choose from the supported players, or supply your own player command (full functionality not guaranteed)"
|
||||
msg2="if using an unsupported player, it must be able to play URLs for streaming from the internet"
|
||||
if ((IS_ROFI)); then
|
||||
PLAYER_FN=$(
|
||||
awk '{print $NF}' < <(rofi -dmenu -config "$CFG_FILE" -DPI "$DPI" \
|
||||
-l 4 -theme-str 'listview {columns: 1;} window {width: 40%;}' \
|
||||
-p "Enter video player:" -window-title 'aniwrapper' \
|
||||
-mesg "$(printf "%s\n%s\n" "$(generate_span "$msg1")" "$(generate_span "$msg2")")" \
|
||||
-a 0 -sep '|' <<< "$SUPPORTED_PLAYERS")
|
||||
)
|
||||
else
|
||||
printf "%s\n%s\n" "$msg1" "$msg2"
|
||||
printf "%s\n" "SUPPORTED PLAYERS:"
|
||||
while IFS='|' read -ra players; do
|
||||
printf "%s\n" "${players[@]}"
|
||||
done <<< "$SUPPORTED_PLAYERS"
|
||||
prompt "Enter player"
|
||||
read -r PLAYER_FN
|
||||
fi
|
||||
if ((IS_ROFI == 0 && IS_DOWNLOAD == 0)); then
|
||||
run -c "$@"
|
||||
exit $?
|
||||
elif ((IS_ROFI == 0 && IS_DOWNLOAD == 1)); then
|
||||
printf "%s" "Enter download dir: "
|
||||
[ -z "$PLAYER_FN" ] && PLAYER_FN=mpv
|
||||
if ! command -v "$PLAYER_FN" > /dev/null; then
|
||||
die "ERROR: $PLAYER_FN does not exist"
|
||||
fi
|
||||
}
|
||||
|
||||
# prompts the user to select a provider and returns the provider name and index
|
||||
get_provider() {
|
||||
providers="1. Animixplay|2. Xstreamcdn|3. Gogoanime"
|
||||
if ((IS_ROFI)); then
|
||||
selection="$(rofi -dmenu -config "$CFG_FILE" -DPI "$DPI" \
|
||||
-i -l 7 -theme-str 'listview {columns: 1;} window {width: 45%;}' \
|
||||
-p "Select provider:" -window-title 'aniwrapper' \
|
||||
-a 0 -sep '|' <<< "$providers")"
|
||||
[ -z "$selection" ] && selection=1
|
||||
provider_idx="${selection:0:1}"
|
||||
else
|
||||
provider_begin=1
|
||||
provider_end=3
|
||||
printf "%s%s\n" "Select provider:" "[$providers]"
|
||||
prompt "Enter provider [$provider_begin-$provider_end]"
|
||||
read -r provider_idx
|
||||
[ -z "$provider_idx" ] && die "ERROR: provider index cannot be empty"
|
||||
((provider_idx < provider_begin || provider_idx > provider_end)) && die "ERROR: provider index must be between $provider_begin and $provider_end"
|
||||
fi
|
||||
while IFS='|' read -ra providers_list; do
|
||||
for p in "${providers_list[@]}"; do
|
||||
if [[ "${p:0:1}" == "$provider_idx" ]]; then
|
||||
lg "provider -> $p | provider index -> $idx" > /dev/stderr
|
||||
provider="${p:3}"
|
||||
break
|
||||
fi
|
||||
((++idx))
|
||||
done
|
||||
done <<< "$providers"
|
||||
[ -z "$provider" ] && provider="Xstreamcdn"
|
||||
inf "Selected provider: $provider"
|
||||
}
|
||||
|
||||
# Check passed in flags and set cli arguments
|
||||
check_flags() {
|
||||
if ((IS_VERBOSE && SILENT)); then
|
||||
die "verbose and silent options cannot be used together"
|
||||
fi
|
||||
if ((IS_DOWNLOAD && IS_AUTOPLAY)); then
|
||||
die "autoplay and download options cannot be used together"
|
||||
fi
|
||||
if ((IS_DOWNLOAD && IS_PLAY_FROM_FILE)); then
|
||||
die "download and play from file options cannot be used together"
|
||||
fi
|
||||
if ((!IS_DOWNLOAD && IS_ALTERNATE_PLAYER)); then
|
||||
get_player
|
||||
lg "SELECTED PLAYER FN -> $PLAYER_FN"
|
||||
fi
|
||||
args=()
|
||||
if ((IS_AUTOPLAY)); then
|
||||
args+=(-a)
|
||||
fi
|
||||
if ((!IS_ROFI)); then
|
||||
args+=(-c)
|
||||
prompt "Enter download directory"
|
||||
read -r dl_dir
|
||||
lg "Download dir: $dl_dir"
|
||||
if [ ! -d "$dl_dir" ]; then
|
||||
mkdir -p "$dl_dir" || seppuku "Error creating directory: $dl_dir"
|
||||
mkdir -p "$dl_dir" || die "Error creating directory: $dl_dir"
|
||||
fi
|
||||
run "-cd $dl_dir" "$@"
|
||||
exit $?
|
||||
elif ((IS_ROFI == 1 && IS_PLAY_FROM_FILE == 1 && IS_CUSTOM_THEME == 1)); then
|
||||
run "-f$play_path" -T "$CFG_FILE" "$@"
|
||||
exit $?
|
||||
elif ((IS_ROFI == 1 && IS_PLAY_FROM_FILE == 1 && IS_CUSTOM_THEME == 0)); then
|
||||
run "-f$play_path" -t "$theme" "$@"
|
||||
args+=(-d"$dl_dir")
|
||||
fi
|
||||
if ((IS_DOWNLOAD)); then
|
||||
args+=(-d "$DEFAULT_DOWNLOAD")
|
||||
fi
|
||||
if ((IS_PLAY_FROM_FILE)); then
|
||||
args+=(-f"$play_path")
|
||||
fi
|
||||
if ((IS_ALTERNATE_PLAYER)); then
|
||||
args+=(-p "$PLAYER_FN")
|
||||
fi
|
||||
if ((IS_RESUME)); then
|
||||
args+=(-r)
|
||||
fi
|
||||
if ((SELECT_PROVIDER)); then
|
||||
get_provider || provider_idx=1
|
||||
lg "PROVIDER INDEX -> $provider_idx"
|
||||
args+=(-P"$provider_idx")
|
||||
fi
|
||||
if ((SILENT)); then
|
||||
args+=(-S)
|
||||
fi
|
||||
if ((IS_VERBOSE)); then
|
||||
args+=(-v)
|
||||
fi
|
||||
if ((GET_QUALITY)); then
|
||||
args+=(-q)
|
||||
fi
|
||||
if ((!IS_SELECT_EPISODE)); then
|
||||
args+=(-e"$episodes")
|
||||
fi
|
||||
|
||||
lg "ARGS: ${args[*]}"
|
||||
if ((IS_AUTOPLAY || IS_DOWNLOAD || !IS_ROFI || IS_RESUME || IS_PLAY_FROM_FILE)); then
|
||||
run "${args[@]}" "$@"
|
||||
exit $?
|
||||
fi
|
||||
}
|
||||
@ -248,21 +363,23 @@ check_flags() {
|
||||
get_dl_dir() {
|
||||
dl_dir=$(
|
||||
rofi -dpi "$DPI" -dmenu -config "$CFG_FILE" \
|
||||
-theme-str 'listview {columns: 1;} window {width: 45%;}' \
|
||||
-mesg "$(generate_span "Enter the path to the download directory, or leave blank to go with the default: $HOME/Videos/sauce/")" \
|
||||
-l 1 -p "Enter download dir:"
|
||||
-l 1 -p "Enter download dir:" -window-title 'aniwrapper'
|
||||
)
|
||||
# if dl_dir is none set to current directory
|
||||
[ "$dl_dir" == "" ] && dl_dir="$DEFAULT_DOWNLOAD"
|
||||
if [ ! -d "$dl_dir" ]; then
|
||||
mkdir -p "$dl_dir" || die "Error creating directory: $dl_dir"
|
||||
fi
|
||||
}
|
||||
|
||||
########
|
||||
# Main #
|
||||
########
|
||||
main() {
|
||||
((SILENT != 1)) && lg "CONFIG DIR: $CFG_DIR"
|
||||
((SILENT != 1)) && lg "ROFI CFG: $CFG_FILE"
|
||||
choice=$(echo "${options[@]}" | rofi -dpi "$DPI" -dmenu -only-match -sep '|' \
|
||||
-config "$CFG_FILE" -l 7 -i -p "Aniwrapper")
|
||||
((!SILENT)) && lg "CONFIG DIR: $CFG_DIR"
|
||||
((!SILENT)) && lg "ROFI CFG: $CFG_FILE"
|
||||
choice=$(echo "${options[@]}" | rofi -dpi "$DPI" -dmenu -no-custom -sep '|' \
|
||||
-theme-str 'listview {columns: 2;} window {width: 45%;}' \
|
||||
-config "$CFG_FILE" -l 4 -i -p "Aniwrapper" -window-title 'aniwrapper')
|
||||
|
||||
[ "$choice" == "$quit" ] && quit
|
||||
|
||||
@ -270,54 +387,54 @@ main() {
|
||||
|
||||
case "$selection" in
|
||||
1.)
|
||||
# ---------------------------------------------------------------------------
|
||||
# streaming
|
||||
# ---------------------------------------------------------------------------
|
||||
lg "Streaming mode"
|
||||
run
|
||||
;;
|
||||
2.)
|
||||
# ---------------------------------------------------------------------------
|
||||
# download
|
||||
# ---------------------------------------------------------------------------
|
||||
lg "Download anime"
|
||||
get_dl_dir && run -d "$dl_dir"
|
||||
;;
|
||||
3.)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# continue
|
||||
# ---------------------------------------------------------------------------
|
||||
lg "Continue watching"
|
||||
run -H
|
||||
;;
|
||||
4.)
|
||||
# ---------------------------------------------------------------------------
|
||||
# play
|
||||
# ---------------------------------------------------------------------------
|
||||
lg "Showing recently updated anime"
|
||||
run -R
|
||||
;;
|
||||
5.)
|
||||
lg "Play from file selected"
|
||||
IS_PLAY_FROM_FILE=1
|
||||
span=$(printf '%s\n%s\n' "$(generate_span "Provide a valid path to a directory or leave blank to go with the default: $HOME/Videos/sauce/")" "$(generate_span "The program will begin searching for media files from the supplied directory")")
|
||||
play_dir=$(rofi -dpi "$DPI" -dmenu -config "$CFG_FILE" \
|
||||
-l 1 -mesg "$span" -p "Enter path to starting directory:")
|
||||
span=$(printf '%s\n%s\n' "$(generate_span "Provide a path to a valid directory, or choose from the list below")" "$(generate_span "The program will begin searching for media files from the supplied directory")")
|
||||
play_dir=$(
|
||||
rofi -dpi "$DPI" -dmenu -config "$CFG_FILE" \
|
||||
-i -l 12 -mesg "$span" -p "Enter path to starting directory:" \
|
||||
-async-pre-read 24 -matching 'fuzzy' -window-title 'aniwrapper' \
|
||||
-sort -sorting-method fzf \
|
||||
< <(sqlite3 -noheader -list "$CFG_DIR/history.sqlite3" <<< "SELECT directory FROM file_history WHERE filename = 'DIRECTORY' ORDER BY WATCH_DATE DESC;")
|
||||
)
|
||||
# trim trailing whitespace
|
||||
play_dir="${play_dir%% }"
|
||||
lg "Play dir: $play_dir"
|
||||
if [ -z "$play_dir" ]; then
|
||||
mkdir -p "$DEFAULT_DOWNLOAD" || seppuku "error creating default download directory"
|
||||
mkdir -p "$DEFAULT_DOWNLOAD" || die "error creating default download directory"
|
||||
run -f"$DEFAULT_DOWNLOAD"
|
||||
else
|
||||
run -f"$play_dir"
|
||||
fi
|
||||
exit $?
|
||||
;;
|
||||
5.)
|
||||
6.)
|
||||
lg "Sync history database"
|
||||
IS_SYNC=1
|
||||
roficmd="rofi -dpi $DPI -dmenu -config $CFG_FILE -l 0 -p"
|
||||
username=$($roficmd "Enter the username of the remote user:")
|
||||
[ -z "$username" ] && seppuku "No username provided... exiting"
|
||||
host=$($roficmd "Enter the host for the remote machine (eg 192.168.1.99):")
|
||||
[ -z "$host" ] && seppuku "No host provided... exiting"
|
||||
port=$($roficmd "Enter in the ssh port for remote machine or leave blank for default [22]:")
|
||||
username=$($roficmd "Enter the username of the remote user:" -theme-str 'window {width: 45%;}')
|
||||
[ -z "$username" ] && die "No username provided... exiting"
|
||||
host=$($roficmd "Enter the host for the remote machine (eg 192.168.1.99):" -theme-str 'window {width: 45%;}')
|
||||
[ -z "$host" ] && die "No host provided... exiting"
|
||||
port=$($roficmd "Enter in the ssh port for remote machine or leave blank for default [22]:" -theme-str 'window {width: 45%;}')
|
||||
[ -z "$port" ] && port=22
|
||||
keypath=$($roficmd "Enter path to private key (leave blank if not needed or if unsure):")
|
||||
keypath=$($roficmd "Enter path to private key (leave blank if not needed or if unsure):" -theme-str 'window {width: 45%;}')
|
||||
if ! printf "%s\n%s\n%d\n%s\n" "$username" "$host" "$port" "$keypath" | run -s; then
|
||||
lg "Aniwrapper was unable to sync the databases..."
|
||||
exit 1
|
||||
@ -326,22 +443,20 @@ main() {
|
||||
quit
|
||||
fi
|
||||
;;
|
||||
6.)
|
||||
# -----------------------------------------------------------------
|
||||
# choose theme
|
||||
# -----------------------------------------------------------------
|
||||
[ -z "$THEMES" ] && seppuku "No themes provided... exiting"
|
||||
choice=$(rofi -dmenu -config "$CFG_FILE" -dpi "$DPI" \
|
||||
-only-match -l 4 -i -p "Choose theme: " -sep '|' \
|
||||
-theme-str 'listview { columns: 2; }' <<< "$THEMES")
|
||||
7.)
|
||||
[ -z "$THEMES" ] && die "No themes provided... exiting"
|
||||
theme_idx="$(get_theme_idx)"
|
||||
lg "Theme index: $theme_idx"
|
||||
lg "NUM THEMES: $NUM_THEMES"
|
||||
choice=$(rofi -dmenu -config "$CFG_FILE" -dpi "$DPI" -window-title 'aniwrapper' \
|
||||
-theme-str 'listview {columns: 2;} window {width: 45%;}' \
|
||||
-no-custom -l 5 -i -p "Choose theme: " -sep '|' \
|
||||
-a "$theme_idx" -selected-row "$theme_idx" <<< "$THEMES")
|
||||
theme=$(awk '{ print $1 }' <<< "$choice")
|
||||
set_theme "$theme"
|
||||
main
|
||||
;;
|
||||
7.)
|
||||
# -----------------------------------------------------------------
|
||||
# get out
|
||||
# -----------------------------------------------------------------
|
||||
8.)
|
||||
quit
|
||||
;;
|
||||
*)
|
||||
@ -354,9 +469,9 @@ parse_args "$@"
|
||||
shift $((OPTIND - 1))
|
||||
if [ $# -gt 0 ]; then
|
||||
check_flags "$*"
|
||||
if [ "$IS_DOWNLOAD" -eq 0 ]; then
|
||||
if ((!IS_DOWNLOAD)); then
|
||||
run "$*"
|
||||
elif [ "$IS_DOWNLOAD" -eq 1 ]; then
|
||||
elif ((IS_DOWNLOAD)); then
|
||||
get_dl_dir && run -d "$dl_dir" "$*"
|
||||
fi
|
||||
else
|
||||
|
44
disclaimer.md
Normal file
44
disclaimer.md
Normal file
@ -0,0 +1,44 @@
|
||||
<h1 align="center">Disclaimer</h1>
|
||||
|
||||
<div align="center">
|
||||
|
||||
<h2>This project: aniwrapper</h2>
|
||||
|
||||
<br>
|
||||
|
||||
The core aim of this project is to co-relate automation and efficiency to extract what is provided to an user on the internet. Every content available in the project is hosted by external non-affiliated sources.
|
||||
|
||||
<br>
|
||||
|
||||
<b>Any content served through this project is publicly accessible. If your site is listed in this project, the code is pretty much public. Take necessary measures to counter the exploits used to extract content in your site.</b>
|
||||
|
||||
Think of this project as your normal browser, but a bit more straight-forward and specific. While an average browser makes hundreds of requests to get everything from a site, this project goes on to make requests associated with only getting the content served by the sites.
|
||||
|
||||
<b>
|
||||
|
||||
This project is to be used at the user's own risk, based on their government and laws.
|
||||
|
||||
This project has no control on the content it is serving, using copyrighted content from the providers is not going to be accounted for by the developer. It is the user's own risk.
|
||||
|
||||
</b>
|
||||
|
||||
<br>
|
||||
|
||||
<h2>DMCA and Copyright Infrigements</h2>
|
||||
|
||||
<br>
|
||||
|
||||
<b>
|
||||
A browser is a tool, and the maliciousness of the tool is directly based on the user.
|
||||
</b>
|
||||
|
||||
This project uses client-side content access mechanisms. Hence, the copyright infrigements or DMCA in this project's regards are to be forwarded to the associated site by the associated notifier of any such claims. As of writing this is gogoplay
|
||||
|
||||
<b> Do not harass the maintainer. </b>
|
||||
|
||||
<h2>Contacting the maintainer</h2>
|
||||
<br>
|
||||
|
||||
Begin by making a GitHub issue or sending an email to suda@sudacode.com
|
||||
|
||||
</div>
|
60
docs/aniwrapper-menus.md
Normal file
60
docs/aniwrapper-menus.md
Normal file
@ -0,0 +1,60 @@
|
||||
# Search Anime
|
||||
|
||||
<div align="center">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
The first menu consists of a search box and a list of anime titles corresponding to past valid searches. Choose an option from the menu, or enter in a unique search query to search for a new anime. The result from this will be used to query against `gogoanime` and return similar named anime
|
||||
|
||||
If selecting an anime from the provided list, the [anime selection](#anime-selection) menu will be skipped and the program will move on to [episode selection](#episode-selection) for the chosen anime
|
||||
|
||||
# Anime Selection
|
||||
|
||||
<div align="center">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
The next menu is where you select the anime to watch from a narrowed down list of candidates. Titles that are highlighed in blue indicate that anime has been selected before
|
||||
|
||||
# Episode Selection
|
||||
|
||||
<div align="center">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
Here you will be prompted to select the episode(s) to download
|
||||
|
||||
Multiple episodes can be downloaded by giving the episode range like so
|
||||
|
||||
```
|
||||
Select Episode [1-13]: 1 6
|
||||
```
|
||||
|
||||
This would open/download episodes 1 2 3 4 5 6
|
||||
|
||||
# Play from File
|
||||
|
||||
<div align="center">
|
||||
|
||||

|
||||

|
||||
|
||||
</div>
|
||||
|
||||
In this option, you provide the program with a path, and it will begin searching the directory for subfolders or playable media in the current directory. Once a file is found, it will be opened in `mpv`
|
||||
|
||||
# Choose Theme
|
||||
|
||||
<div align="center">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
Choose the `rofi` theme to use from the presets. Theme selection will persist through the duration of the program
|
148
docs/man/aniwrapper.1
Normal file
148
docs/man/aniwrapper.1
Normal file
@ -0,0 +1,148 @@
|
||||
.\" Automatically generated by Pandoc 2.19.2
|
||||
.\"
|
||||
.\" Define V font for inline verbatim, using C font in formats
|
||||
.\" that render this, and otherwise B font.
|
||||
.ie "\f[CB]x\f[]"x" \{\
|
||||
. ftr V B
|
||||
. ftr VI BI
|
||||
. ftr VB B
|
||||
. ftr VBI BI
|
||||
.\}
|
||||
.el \{\
|
||||
. ftr V CR
|
||||
. ftr VI CI
|
||||
. ftr VB CB
|
||||
. ftr VBI CBI
|
||||
.\}
|
||||
.TH "ANIWRAPPER" "1" "February 4, 2022" "aniwrapper 1.0.0" "Man Page"
|
||||
.hy
|
||||
.SH NAME
|
||||
.PP
|
||||
aniwrapper - A rofi wrapper around ani-cli: a command-line tool to
|
||||
stream, download, and play anime
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
\f[B]aniwrapper\f[R] [-adhpqrSv] [-t \f[I]theme\f[R] | -T
|
||||
\f[I]config_path\f[R]] [\f[I]query\f[R]]
|
||||
.PD 0
|
||||
.P
|
||||
.PD
|
||||
\f[B]aniwrapper\f[R] -f \f[I]directory_path\f[R] [-t \f[I]theme\f[R] |
|
||||
-T \f[I]config_path\f[R]] [-pSv] [\f[I]query\f[R]]
|
||||
.PD 0
|
||||
.P
|
||||
.PD
|
||||
\f[B]aniwrapper\f[R] -c [-dhpqrSv] [\f[I]query\f[R]]
|
||||
.PD 0
|
||||
.P
|
||||
.PD
|
||||
\f[B]aniwrapper\f[R] -Q \f[I]query\f[R]
|
||||
.PD 0
|
||||
.P
|
||||
.PD
|
||||
\f[B]aniwrapper\f[R] -C
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\f[B]aniwrapper\f[R] is a wrapper around a modified version of
|
||||
\f[B]ani-cli\f[R], which uses \f[B]rofi\f[R] to get user input and
|
||||
control the program flow, as well as a a \f[B]sqlite3\f[R] database for
|
||||
tracking search/watch history
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
Defaults:
|
||||
.IP \[bu] 2
|
||||
\f[B]rofi\f[R] enabled
|
||||
.IP \[bu] 2
|
||||
aniwrapper.rasi theme
|
||||
.IP \[bu] 2
|
||||
best quality
|
||||
.TP
|
||||
\f[B]-a\f[R]
|
||||
Enable autoplay in streaming mode
|
||||
.TP
|
||||
\f[B]-c\f[R]
|
||||
Enable command-line mode (disable \f[B]rofi\f[R])
|
||||
.TP
|
||||
\f[B]-C\f[R]
|
||||
Connect to the history database
|
||||
\f[I]$XDG_CONFIG_HOME/aniwrapper/history.sqlite3\f[R]
|
||||
.TP
|
||||
\f[B]-d\f[R]
|
||||
Enable downloading anime in command-line mode
|
||||
.TP
|
||||
\f[B]-e\f[R] \f[I]episode\f[R] \f[B]or\f[R] \f[I]begin_episode - end_episode\f[R]
|
||||
Select episode(s) to stream/download
|
||||
.TP
|
||||
\f[B]-f\f[R]
|
||||
Specify the starting search directory for \[lq]Play from File\[rq] mode
|
||||
.TP
|
||||
\f[B]-h\f[R]
|
||||
Display the help message
|
||||
.TP
|
||||
\f[B]-p\f[R]
|
||||
Enable video player selection menu
|
||||
.TP
|
||||
\f[B]-P\f[R]
|
||||
Enable provider selection menu
|
||||
.TP
|
||||
\f[B]-q\f[R]
|
||||
Enable quality selection
|
||||
.TP
|
||||
\f[B]-r\f[R]
|
||||
Start script at episode selection for the most recently watched anime
|
||||
.TP
|
||||
\f[B]-Q\f[R] \f[I]query\f[R]
|
||||
Run a query on the history databse
|
||||
.TP
|
||||
\f[B]-S\f[R]
|
||||
Enable silent mode (suppress all output) [cannot be used with
|
||||
\f[B]-v\f[R]]
|
||||
.TP
|
||||
\f[B]-t\f[R] \f[I]alter|aniwrapper (default)|dracula|doomone|fancy|flamingo|material|monokai|nord|onedark\f[R]
|
||||
Choose theme from presets
|
||||
.TP
|
||||
\f[B]-T\f[R] \f[I]path_to_theme\f[R]
|
||||
Provide custom \f[B]rofi\f[R] theme
|
||||
.TP
|
||||
\f[B]-v\f[R]
|
||||
Verbose output
|
||||
.SH EXAMPLES
|
||||
.TP
|
||||
\f[B]aniwrapper\f[R]
|
||||
Launch main menu with default options
|
||||
.TP
|
||||
\f[B]aniwrapper konosuba\f[R]
|
||||
Run in \f[I]stream\f[R] mode with a \f[I]search query\f[R] =
|
||||
\[lq]konosuba\[rq]
|
||||
.TP
|
||||
\f[B]aniwrapper -qd naruto\f[R]
|
||||
Run in \f[I]download\f[R] mode with \f[I]quality selection enabled\f[R]
|
||||
and a \f[I]search query\f[R] = \[lq]naruto\[rq]
|
||||
.TP
|
||||
\f[B]aniwrapper -vqt doomone\f[R]
|
||||
Run with \f[I]quality selection enabled\f[R] and the \f[I]doomone\f[R]
|
||||
theme
|
||||
.TP
|
||||
\f[B]aniwrapper -cqd\f[R]
|
||||
Run in \f[I]command-line\f[R] \f[I]download\f[R] mode with \f[I]quality
|
||||
selection enabled\f[R] (\f[B]rofi\f[R] disabled)
|
||||
.TP
|
||||
\f[B]aniwrapper -Q \[lq]SELECT * FROM watch_history ORDER BY watch_date DESC LIMIT 10;\[rq]\f[R]
|
||||
Query history database for your 10 most recently watched anime
|
||||
.TP
|
||||
\f[B]aniwrapper -f /media/videos -t dracula\f[R]
|
||||
Run in \f[I]Play from File\f[R] mode, using the \f[I]dracula\f[R] theme,
|
||||
and with the \f[I]search\f[R] starting from \f[I]/media/videos\f[R]
|
||||
.TP
|
||||
\f[B]aniwrapper -S\f[R]
|
||||
Run in \f[I]silent\f[R] mode (suppress all output to stdout and disable
|
||||
notifications)
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
\f[B]rofi(1), rofi-theme(5), rofi-keys(5), sqlite3(1)\f[R]
|
||||
.SH AUTHOR
|
||||
.PP
|
||||
Written by Kyle Yasuda <ksyasuda@umich.edu>
|
||||
.PP
|
||||
Original code based on pystardust\[cq]s \f[I]ani-cli\f[R]
|
||||
(<https://github.com/pystardust/ani-cli>)
|
118
docs/man/aniwrapper.1.md
Normal file
118
docs/man/aniwrapper.1.md
Normal file
@ -0,0 +1,118 @@
|
||||
---
|
||||
title: ANIWRAPPER
|
||||
section: 1
|
||||
header: Man Page
|
||||
footer: aniwrapper 1.0.0
|
||||
date: February 4, 2022
|
||||
---
|
||||
|
||||
# NAME
|
||||
|
||||
aniwrapper - A rofi wrapper around ani-cli: a command-line tool to stream, download, and play anime
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
**aniwrapper** [-adhpqrSv] [-t _theme_ | -T _config_path_] [_query_]\
|
||||
**aniwrapper** -f _directory_path_ [-t _theme_ | -T _config_path_] [-pSv] [_query_]\
|
||||
**aniwrapper** -c [-dhpqrSv] [_query_]\
|
||||
**aniwrapper** -Q _query_\
|
||||
**aniwrapper** -C
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
**aniwrapper** is a wrapper around a modified version of **ani-cli**, which uses
|
||||
**rofi** to get user input and control the program flow, as well as a
|
||||
a **sqlite3** database for tracking search/watch history
|
||||
|
||||
# OPTIONS
|
||||
|
||||
Defaults:
|
||||
|
||||
- **rofi** enabled
|
||||
- aniwrapper.rasi theme
|
||||
- best quality
|
||||
|
||||
**-a**
|
||||
: Enable autoplay in streaming mode
|
||||
|
||||
**-c**
|
||||
: Enable command-line mode (disable **rofi**)
|
||||
|
||||
**-C**
|
||||
: Connect to the history database _$XDG_CONFIG_HOME/aniwrapper/history.sqlite3_
|
||||
|
||||
**-d**
|
||||
: Enable downloading anime in command-line mode
|
||||
|
||||
**-e** _episode_ **or** _begin_episode - end_episode_
|
||||
: Select episode(s) to stream/download
|
||||
|
||||
**-f**
|
||||
: Specify the starting search directory for "Play from File" mode
|
||||
|
||||
**-h**
|
||||
: Display the help message
|
||||
|
||||
**-p**
|
||||
: Enable video player selection menu
|
||||
|
||||
**-P**
|
||||
: Enable provider selection menu
|
||||
|
||||
**-q**
|
||||
: Enable quality selection
|
||||
|
||||
**-r**
|
||||
: Start script at episode selection for the most recently watched anime
|
||||
|
||||
**-Q** _query_
|
||||
: Run a query on the history databse
|
||||
|
||||
**-S**
|
||||
: Enable silent mode (suppress all output) [cannot be used with **-v**]
|
||||
|
||||
**-t** _alter|aniwrapper (default)|dracula|doomone|fancy|flamingo|material|monokai|nord|onedark_
|
||||
: Choose theme from presets
|
||||
|
||||
**-T** _path_to_theme_
|
||||
: Provide custom **rofi** theme
|
||||
|
||||
**-v**
|
||||
: Verbose output
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
**aniwrapper**
|
||||
: Launch main menu with default options
|
||||
|
||||
**aniwrapper konosuba**
|
||||
: Run in _stream_ mode with a _search query_ = "konosuba"
|
||||
|
||||
**aniwrapper -qd naruto**
|
||||
: Run in _download_ mode with _quality selection enabled_ and a _search query_ =
|
||||
"naruto"
|
||||
|
||||
**aniwrapper -vqt doomone**
|
||||
: Run with _quality selection enabled_ and the _doomone_ theme
|
||||
|
||||
**aniwrapper -cqd**
|
||||
: Run in _command-line_ _download_ mode with _quality selection enabled_ (**rofi** disabled)
|
||||
|
||||
**aniwrapper -Q "SELECT \* FROM watch_history ORDER BY watch_date DESC LIMIT 10;"**
|
||||
: Query history database for your 10 most recently watched anime
|
||||
|
||||
**aniwrapper -f /media/videos -t dracula**
|
||||
: Run in _Play from File_ mode, using the _dracula_ theme, and with the _search_ starting from _/media/videos_
|
||||
|
||||
**aniwrapper -S**
|
||||
: Run in _silent_ mode (suppress all output to stdout and disable notifications)
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
**rofi(1), rofi-theme(5), rofi-keys(5), sqlite3(1)**
|
||||
|
||||
# AUTHOR
|
||||
|
||||
Written by Kyle Yasuda <ksyasuda@umich.edu>
|
||||
|
||||
Original code based on pystardust's _ani-cli_ (<https://github.com/pystardust/ani-cli>)
|
171
lib/ani-cli/UI
Normal file
171
lib/ani-cli/UI
Normal file
@ -0,0 +1,171 @@
|
||||
#!/usr/bin/env bash
|
||||
VERSION="1.0.0"
|
||||
|
||||
retry() {
|
||||
err "$*"
|
||||
prompt
|
||||
}
|
||||
|
||||
# display error message and exit
|
||||
die() {
|
||||
((!SILENT)) && printf "\033[1;31m%s\033[0m\n" "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# display an error message to stderr (in red)
|
||||
err() {
|
||||
((!SILENT)) && printf "\33[2K\r\033[1;31m%s\033[0m\n" "$*" >&2
|
||||
}
|
||||
|
||||
# display a log message if verbose mode is enabled
|
||||
lg() {
|
||||
((VERBOSE)) && printf "\033[1;35m%s\033[0m\n" "$*" >&2
|
||||
}
|
||||
|
||||
# display an informational message (first argument in green, second in magenta)
|
||||
inf() {
|
||||
printf "\33[2K\r\033[1;35m%s \033[1;35m%s\033[0m\n" "$1" "$2"
|
||||
}
|
||||
|
||||
progress() {
|
||||
((!SILENT)) && printf "\33[2K\r\033[1;34m%s\033[0m\n" "$1" >&2
|
||||
}
|
||||
|
||||
# prompts the user with message in $1-2 ($1 in blue, $2 in magenta) and saves the input to the variables in $REPLY and $REPLY2
|
||||
prompt() {
|
||||
printf "\033[1;35m%s\033[1;35m%s\033[1;34m\033[0m: " "$1" "$2"
|
||||
}
|
||||
|
||||
# displays an even (cyan) line of a menu line with $2 as an indicator in [] and $1 as the option
|
||||
menu_line_even() {
|
||||
printf "\033[1;36m(\033[1;36m%s\033[1;36m) \033[1;36m%s\033[0m\n" "$2" "$1"
|
||||
}
|
||||
|
||||
# displays an odd (yellow) line of a menu line with $2 as an indicator in [] and $1 as the option
|
||||
menu_line_odd() {
|
||||
printf "\033[1;33m(\033[1;33m%s\033[1;33m) \033[1;33m%s\033[0m\n" "$2" "$1"
|
||||
}
|
||||
|
||||
# display alternating menu lines (even and odd)
|
||||
menu_line_alternate() {
|
||||
menu_line_parity=${menu_line_parity:-0}
|
||||
if [ "$menu_line_parity" -eq 0 ]; then
|
||||
menu_line_odd "$1" "$2"
|
||||
menu_line_parity=1
|
||||
else
|
||||
menu_line_even "$1" "$2"
|
||||
menu_line_parity=0
|
||||
fi
|
||||
}
|
||||
|
||||
# displays a warning (red) line of a menu line with $2 as an indicator in [] and $1 as the option
|
||||
menu_line_strong() {
|
||||
printf "\033[1;34m[\033[1;33m%s\033[1;34m] \033[1;33m%s\033[0m\n" "$2" "$1"
|
||||
}
|
||||
|
||||
# Select anime from query results
|
||||
anime_selection() {
|
||||
search_results=$*
|
||||
count=1
|
||||
while read -r anime_id; do
|
||||
anime_id=$(printf "%s" "$anime_id" | sed -E 's/\-episode\-.*//')
|
||||
menu_line_alternate "$anime_id" "$count"
|
||||
: count=$((count += 1))
|
||||
done <<< "$search_results"
|
||||
prompt "Enter choice"
|
||||
read -r choice
|
||||
|
||||
# Check if input is a number
|
||||
[[ "$choice" -eq "$choice" ]] 2> /dev/null || die "Invalid number entered"
|
||||
|
||||
count=1
|
||||
while read -r anime_id; do
|
||||
if [[ "$count" -eq "$choice" ]]; then
|
||||
anime_id=$(printf "%s" "$anime_id" | sed -E 's/\-episode\-.*//')
|
||||
selection_id=$anime_id
|
||||
break
|
||||
fi
|
||||
count=$((count + 1))
|
||||
done <<< "$search_results"
|
||||
|
||||
[[ -z "$selection_id" ]] && die "Invalid number entered"
|
||||
insert_history "search" "$selection_id" &
|
||||
lg "Selection: $selection_id"
|
||||
progress "(Gogoanime) Searching Episodes.."
|
||||
episode_list "$selection_id"
|
||||
return 0
|
||||
}
|
||||
|
||||
# select episode from query results
|
||||
episode_selection() {
|
||||
ep_choice_start=1
|
||||
if [ -n "$LAST_EP_NUMBER" ]; then
|
||||
[[ "$is_download" -eq 1 ]] &&
|
||||
inf "Range of episodes can be specified:" "start_number end_number"
|
||||
inf "Anime:" "$anime_id"
|
||||
prompt "Choose episode " "[$FIRST_EP_NUMBER-$LAST_EP_NUMBER]"
|
||||
read -r ep_choice_start ep_choice_end
|
||||
[[ -z "$ep_choice_end" ]] && ep_choice_end="$ep_choice_start"
|
||||
fi
|
||||
if (((ep_choice_start < 0 || ep_choice_start > LAST_EP_NUMBER) || ep_choice_end < ep_choice_start || ep_choice_end > LAST_EP_NUMBER)); then
|
||||
die "Invalid episode/range entered: ep_start -> $ep_choice_start | ep_end -> $ep_choice_end"
|
||||
fi
|
||||
}
|
||||
|
||||
continue_watching() {
|
||||
inf "Continue watching $selection_id?"
|
||||
prompt "Next episode -> $((episode + 1)) [Y/n]"
|
||||
read -r choice
|
||||
[ -z "$choice" ] && choice="y"
|
||||
[[ "$choice" =~ ^(y|Y|Yes)$ ]] && return 0 || return 1
|
||||
}
|
||||
|
||||
# get the search query from user or from args
|
||||
get_search_query() {
|
||||
if [ $# -gt 0 ]; then
|
||||
query="${*// /-}"
|
||||
else
|
||||
prompt "Search Anime"
|
||||
read -r query
|
||||
query="${query// /-}"
|
||||
fi
|
||||
}
|
||||
|
||||
get_dl_dir() {
|
||||
prompt "Enter download directory"
|
||||
read -r download_dir
|
||||
lg "Download dir: $download_dir"
|
||||
[ -z "$download_dir" ] && download_dir="$HOME/Videos/sauce/"
|
||||
if [ ! -d "$download_dir" ]; then
|
||||
mkdir -p "$download_dir" || die "Error creating directory: $download_dir"
|
||||
fi
|
||||
}
|
||||
|
||||
# sets the video quality
|
||||
set_video_quality() {
|
||||
qualities="best|worst"
|
||||
prompt "Choose quality [$qualities]"
|
||||
read -r quality
|
||||
while [[ ! "$quality" =~ ($qualities) ]]; do
|
||||
lg "$quality not a valid quality"
|
||||
prompt "Choose quality [$qualities]"
|
||||
read -r quality
|
||||
done
|
||||
[ -z "$quality" ] && die "No quality selected"
|
||||
NEW_QUALITY=1
|
||||
}
|
||||
|
||||
# gets the video quality from the user
|
||||
get_quality() {
|
||||
qualities="best|worst"
|
||||
prompt "Choose quality " "[$qualities]"
|
||||
read -r quality
|
||||
while [[ ! "$quality" =~ ($qualities) ]]; do
|
||||
lg "$quality not a valid quality -> [$qualities]"
|
||||
prompt "Choose quality " "[$qualities]"
|
||||
read -r quality
|
||||
done
|
||||
lg "selected quality: $quality"
|
||||
}
|
||||
|
||||
# vim :ft=sh
|
212
lib/ani-cli/UI-ROFI
Normal file
212
lib/ani-cli/UI-ROFI
Normal file
@ -0,0 +1,212 @@
|
||||
#!/usr/bin/env bash
|
||||
VERSION="1.0.0"
|
||||
|
||||
retry() {
|
||||
err "$*"
|
||||
prompt
|
||||
}
|
||||
|
||||
# display error message and exit
|
||||
die() {
|
||||
((!SILENT)) && printf "\033[1;31m%s\033[0m\n" "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# display an error message to stderr (in red)
|
||||
err() {
|
||||
((!SILENT)) && printf "\33[2K\r\033[1;31m%s\033[0m\n" "$*" >&2
|
||||
}
|
||||
|
||||
# display a log message if verbose mode is enabled
|
||||
lg() {
|
||||
((VERBOSE)) && printf "\033[1;35m%s\033[0m\n" "$*" >&2
|
||||
}
|
||||
|
||||
# display an informational message (first argument in green, second in magenta)
|
||||
inf() {
|
||||
printf "\33[2K\r\033[1;35m%s \033[1;35m%s\033[0m\n" "$1" "$2"
|
||||
}
|
||||
|
||||
progress() {
|
||||
((!SILENT)) && printf "\33[2K\r\033[1;34m%s\033[0m\n" "$1" >&2
|
||||
}
|
||||
|
||||
# prompts the user with message in $1-2 ($1 in blue, $2 in magenta) and saves the input to the variables in $REPLY and $REPLY2
|
||||
prompt() {
|
||||
printf "\033[1;35m%s\033[1;35m%s\033[1;34m\033[0m: " "$1" "$2"
|
||||
}
|
||||
|
||||
# displays an even (cyan) line of a menu line with $2 as an indicator in [] and $1 as the option
|
||||
menu_line_even() {
|
||||
printf "\033[1;36m(\033[1;36m%s\033[1;36m) \033[1;36m%s\033[0m\n" "$2" "$1"
|
||||
}
|
||||
|
||||
# displays an odd (yellow) line of a menu line with $2 as an indicator in [] and $1 as the option
|
||||
menu_line_odd() {
|
||||
printf "\033[1;33m(\033[1;33m%s\033[1;33m) \033[1;33m%s\033[0m\n" "$2" "$1"
|
||||
}
|
||||
|
||||
# display alternating menu lines (even and odd)
|
||||
menu_line_alternate() {
|
||||
menu_line_parity=${menu_line_parity:-0}
|
||||
if [ "$menu_line_parity" -eq 0 ]; then
|
||||
menu_line_odd "$1" "$2"
|
||||
menu_line_parity=1
|
||||
else
|
||||
menu_line_even "$1" "$2"
|
||||
menu_line_parity=0
|
||||
fi
|
||||
}
|
||||
|
||||
# displays a warning (red) line of a menu line with $2 as an indicator in [] and $1 as the option
|
||||
menu_line_strong() {
|
||||
printf "\033[1;34m[\033[1;33m%s\033[1;34m] \033[1;33m%s\033[0m\n" "$2" "$1"
|
||||
}
|
||||
|
||||
# Select anime from query results
|
||||
anime_selection() {
|
||||
search_results=$*
|
||||
menu=""
|
||||
searched=""
|
||||
cnt=0
|
||||
while read -r anime_id; do
|
||||
anime_id=$(printf "%s" "$anime_id" | sed -E 's/\-episode\-.*//')
|
||||
[[ -z "$menu" ]] && menu="$((cnt + 1)). $anime_id" ||
|
||||
menu="$menu|$((cnt + 1)). $anime_id"
|
||||
if ! check_db "search" "$anime_id"; then
|
||||
[[ -z "$searched" ]] && searched="$cnt" || searched="$searched, $cnt"
|
||||
fi
|
||||
((++cnt))
|
||||
done <<< "$search_results"
|
||||
menu="$menu|$((++cnt)). Search another anime|$((++cnt)). Quit"
|
||||
|
||||
# get the anime from indexed list
|
||||
msg="$(generate_span "Query: $query")"
|
||||
selection="$(rofi -dpi "$DPI" -dmenu -no-custom \
|
||||
-async-pre-read 33 -config "$ROFI_CFG" -l 15 -i -sep '|' \
|
||||
-mesg "$msg" -a "$searched" -p "Enter selection" -window-title 'aniwrapper' <<< "$menu")"
|
||||
choice="${selection%%.*}" # remmove everything from . to end
|
||||
lg "CHOICE: $choice"
|
||||
if ((choice == cnt)); then
|
||||
die "Quitting"
|
||||
elif ((choice == --cnt)); then
|
||||
stream
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Check if input is a number
|
||||
[[ "$choice" -eq "$choice" ]] 2> /dev/null || die "Invalid number entered"
|
||||
|
||||
count=1
|
||||
while read -r anime_id; do
|
||||
if [[ "$count" -eq "$choice" ]]; then
|
||||
anime_id=$(printf "%s" "$anime_id" | sed -E 's/\-episode\-.*//')
|
||||
selection_id=$anime_id
|
||||
break
|
||||
fi
|
||||
count=$((count + 1))
|
||||
done <<< "$search_results"
|
||||
|
||||
[[ -z "$selection_id" ]] && die "Invalid number entered"
|
||||
insert_history "search" "$selection_id" &
|
||||
lg "Selection: $selection_id"
|
||||
progress "(Gogoanime) Searching Episodes.."
|
||||
episode_list "$selection_id"
|
||||
return 0
|
||||
}
|
||||
|
||||
# select episode from query results
|
||||
episode_selection() {
|
||||
ep_choice_start=1
|
||||
lg "Anime ID: $anime_id"
|
||||
stmt="SELECT episode_number FROM watch_history WHERE anime_name = '$anime_id';"
|
||||
|
||||
# Get Watch History for $anime_id as comma separated list
|
||||
watch_history=""
|
||||
while read -r i; do
|
||||
if ((FIRST_EP_NUMBER == 0)); then
|
||||
[[ -z "$watch_history" ]] && watch_history="$((i))" || watch_history="$watch_history, $((i))"
|
||||
else
|
||||
[[ -z "$watch_history" ]] && watch_history="$((--i))" || watch_history="$watch_history, $((--i))"
|
||||
fi
|
||||
done < <(run_stmt "$stmt")
|
||||
lg "Episode watch history -> $watch_history"
|
||||
|
||||
# get user choice and set the start and end
|
||||
msg1="Anime Name: $anime_id"
|
||||
msg2="Range of episodes can be provided as: START_EPISODE - END_EPISODE"
|
||||
[[ "$is_download" -eq 1 ]] && msg=$(printf "%s\n%s" "$(generate_span "$msg1")" "$(generate_span "$msg2")") || msg=$(printf "%s\n" "$(generate_span "$msg1")")
|
||||
choice=$(
|
||||
seq "$FIRST_EP_NUMBER" "$LAST_EP_NUMBER" |
|
||||
rofi -dpi "$DPI" -dmenu -l 12 \
|
||||
-theme-str 'window {width: 45%;}' \
|
||||
-a "$watch_history" \
|
||||
-p "Select Episode [$FIRST_EP_NUMBER, $LAST_EP_NUMBER]:" \
|
||||
-mesg "$msg" -window-title 'aniwrapper' \
|
||||
-config "$ROFI_CFG"
|
||||
)
|
||||
ep_choice_start=$(printf '%s\n' "${choice}" | awk '{print $1}')
|
||||
ep_choice_end=$(printf '%s\n' "${choice}" | awk '{print $NF}')
|
||||
lg "START: $ep_choice_start | END: $ep_choice_end"
|
||||
if (((ep_choice_start < 0 || ep_choice_start > LAST_EP_NUMBER) || ep_choice_end < ep_choice_start || ep_choice_end > LAST_EP_NUMBER)); then
|
||||
die "Invalid episode/range entered: ep_start -> $ep_choice_start | ep_end -> $ep_choice_end"
|
||||
fi
|
||||
}
|
||||
|
||||
continue_watching() {
|
||||
msg="$(printf '%s\n%s' "$(generate_span "Anime: $anime_id")" "$(generate_span "Next episode: $((episode + 1))")")"
|
||||
choice=$(rofi -dmenu -dpi "$DPI" -config "$ROFI_CFG" \
|
||||
-theme-str 'listview {columns: 1;} window {width: 25%;}' \
|
||||
-i -l 2 -no-custom -sep '|' -a 0 -mesg "$msg" \
|
||||
-p "Continue watching?" -window-title 'aniwrapper' <<< "Yes|No")
|
||||
[[ "$choice" =~ ^(y|Y|Yes)$ ]] && return 0 || return 1
|
||||
}
|
||||
|
||||
# get the search query from user or from args
|
||||
get_search_query() {
|
||||
if [ $# -gt 0 ]; then
|
||||
query="${*// /-}"
|
||||
else
|
||||
stmt="SELECT id || '. ' || anime_name FROM search_history ORDER BY search_date DESC;"
|
||||
msg="Choose from list of searched anime below, or enter a unique name of an anime to search for"
|
||||
query=$(rofi -dpi "$DPI" -dmenu -l 15 -p "Search Anime:" \
|
||||
-mesg "$(generate_span "$msg")" \
|
||||
-config "$ROFI_CFG" -window-title 'aniwrapper' < <(run_stmt "$stmt"))
|
||||
query="${query#*\. }" # remove [1-9]. from beginning of query
|
||||
query="${query// /-}" # replace spaces with -
|
||||
fi
|
||||
}
|
||||
|
||||
get_dl_dir() {
|
||||
download_dir=$(
|
||||
rofi -dpi "$DPI" -dmenu -config "$ROFI_CFG" \
|
||||
-theme-str 'listview {columns: 1;} window {width: 45%;}' \
|
||||
-mesg "$(generate_span "Enter the path to the download directory, or leave blank to go with the default: $HOME/Videos/sauce/")" \
|
||||
-l 1 -p "Enter download dir:" -window-title 'aniwrapper'
|
||||
)
|
||||
[ -z "$download_dir" ] && download_dir="$HOME/Videos/sauce/"
|
||||
if [ ! -d "$download_dir" ]; then
|
||||
mkdir -p "$download_dir" || die "Error creating directory: $download_dir"
|
||||
fi
|
||||
}
|
||||
|
||||
# sets the video quality
|
||||
set_video_quality() {
|
||||
qualities="1. best|2. worst"
|
||||
while IFS='|' read -ra quals; do
|
||||
for q in "${quals[@]}"; do
|
||||
if [[ "$(awk '{ print $NF }' <<< "$q")" == "$quality" ]]; then
|
||||
cur_quality="$((${q:0:1} - 1))"
|
||||
break
|
||||
fi
|
||||
done
|
||||
done <<< "$qualities"
|
||||
choice=$(rofi -dmenu -dpi "$DPI" -config "$ROFI_CFG" \
|
||||
-theme-str 'listview {columns: 1;} window {width: 25%;}' \
|
||||
-i -l 6 -no-custom -sep '|' -a "$cur_quality" -mesg "$(generate_span "Current quality: $quality")" \
|
||||
-p "Choose quality:" -window-title 'aniwrapper' -selected-row "$cur_quality" <<< "$qualities")
|
||||
quality=$(awk '{ print $2 }' <<< "$choice")
|
||||
NEW_QUALITY=1
|
||||
}
|
||||
|
||||
# vim :ft=sh
|
121
lib/ani-cli/UI-play
Normal file
121
lib/ani-cli/UI-play
Normal file
@ -0,0 +1,121 @@
|
||||
# display a log message if verbose mode is enabled
|
||||
lg() {
|
||||
((VERBOSE)) && printf "\033[1;35m%s\033[0m\n" "$*" >&2
|
||||
}
|
||||
|
||||
# display error message and exit
|
||||
die() {
|
||||
((!SILENT)) && printf "\033[1;31m%s\033[0m\n" "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# gets the list of directories and playable files from the passed in directory
|
||||
# sets the $watched list to the list of watched files
|
||||
get_directory_data() {
|
||||
search_dir="$1"
|
||||
inputlist=""
|
||||
watched=""
|
||||
cnt=1
|
||||
[ "$search_dir" = "/" ] && cnt=0 # account for no ../ on /
|
||||
for directory in "$1"/*; do
|
||||
directory="${directory##*/}"
|
||||
[ ! -d "$search_dir/$directory" ] && continue
|
||||
[ -z "$inputlist" ] && inputlist="$directory" || inputlist="$inputlist|$directory"
|
||||
if ! check_db "directory" "$search_dir/$directory"; then
|
||||
lg "$search_dir/$directory opened before... adding $cnt to list" 1> /dev/stderr
|
||||
[ -z "$watched" ] && watched="$cnt" || watched="$watched, $cnt"
|
||||
fi
|
||||
((++cnt))
|
||||
done
|
||||
shopt -s nullglob # set nullglob to avoid printing output if no files with extension exist
|
||||
shopt -s nocaseglob # case insensitive globbing
|
||||
for filename in "$search_dir"/*.{mp4,mkv,ts,mp3,webm}; do
|
||||
filename="${filename##*/}"
|
||||
[ -z "$inputlist" ] && inputlist="$filename" || inputlist="$inputlist|$filename"
|
||||
if ! check_db "file" "$search_dir" "$filename"; then
|
||||
lg "$filename watched before... adding $cnt to list" 1> /dev/stderr
|
||||
[ -z "$watched" ] && watched="$cnt" || watched="$watched, $cnt"
|
||||
fi
|
||||
((++cnt))
|
||||
done
|
||||
shopt -u nullglob
|
||||
shopt -u nocaseglob
|
||||
if [[ -n "$inputlist" && "$search_dir" != / ]]; then
|
||||
inputlist="../|$inputlist|Back|Quit"
|
||||
elif [[ -z "$inputlist" && "$search_dir" != / ]]; then
|
||||
inputlist="../|Back|Quit"
|
||||
elif [[ "$search_dir" = / ]]; then
|
||||
inputlist="$inputlist|Quit"
|
||||
else
|
||||
inputlist="Quit"
|
||||
fi
|
||||
lg "INPUT LIST: $inputlist" 1> /dev/stderr
|
||||
lg "WATCHED LIST: $watched" 1> /dev/stderr
|
||||
}
|
||||
|
||||
# recursive function for finding path to video file given a starting directory
|
||||
find_media() {
|
||||
inp="$1"
|
||||
[ -z "$inp" ] && die "No directory"
|
||||
lg "BEGIN find_media() on $inp" 1> /dev/stderr
|
||||
|
||||
# base case hit when a file is found
|
||||
if [ -f "$inp" ]; then
|
||||
printf "%s\n" "$inp"
|
||||
return 0
|
||||
fi
|
||||
|
||||
get_directory_data "$inp"
|
||||
selection="$(rofi -dpi "$DPI" -dmenu -no-custom -async-pre-read 33 -config "$ROFI_CFG" \
|
||||
-l 15 -i -sep '|' -mesg "$(generate_span "Current directory: $inp")" -a "$watched" \
|
||||
-p "Enter selection" -window-title 'aniwrapper' <<< "$inputlist")"
|
||||
[ -z "$selection" ] && return 1
|
||||
case "$selection" in
|
||||
Back | ../)
|
||||
dotdotslash="${inp%/*}"
|
||||
[ -z "$dotdotslash" ] && dotdotslash="/"
|
||||
insert_history "directory" "$dotdotslash"
|
||||
find_media "$dotdotslash"
|
||||
;;
|
||||
Quit)
|
||||
return 1
|
||||
;;
|
||||
*)
|
||||
if [ -d "$inp/$selection" ]; then
|
||||
insert_history "directory" "$inp/$selection"
|
||||
if [ "$inp" = "/" ]; then
|
||||
find_media "/$selection"
|
||||
else
|
||||
find_media "$inp/$selection"
|
||||
fi
|
||||
else
|
||||
find_media "$inp/$selection"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# opens the passed in file with $PLAYER_FN
|
||||
play_file() {
|
||||
lg "Checking if file is playable"
|
||||
if [[ "$1" =~ (\.mp4|\.mkv|\.ts|\.webm)$ ]]; then
|
||||
filename="${1##*/}"
|
||||
directory="${1%/*}"
|
||||
insert_history "file" "$directory" "$filename"
|
||||
notification "Playing $1"
|
||||
case "$PLAYER_FN" in
|
||||
mpv)
|
||||
nohup "$PLAYER_FN" --force-media-title="aniwrapper: play-from-file - $1" "$1" > /dev/null 2>&1 &
|
||||
;;
|
||||
*)
|
||||
nohup "$PLAYER_FN" "$1" > /dev/null 2>&1 &
|
||||
;;
|
||||
esac
|
||||
return $?
|
||||
else
|
||||
die "File: $1 is not playable... Quitting"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# vim: ft=sh
|
151
lib/ani-cli/db
Normal file
151
lib/ani-cli/db
Normal file
@ -0,0 +1,151 @@
|
||||
# runs sql command on the history database
|
||||
run_stmt() {
|
||||
printf "%s\n" "$1" | sqlite3 -noheader -list "$HISTORY_DB"
|
||||
}
|
||||
|
||||
# Return number of matches for anime/episode in db
|
||||
check_db() {
|
||||
case "$1" in
|
||||
directory)
|
||||
stmt="SELECT COUNT(*) FROM file_history WHERE directory = '$2';"
|
||||
;;
|
||||
file)
|
||||
stmt="SELECT COUNT(*) FROM file_history WHERE directory = '$2' AND filename = '$3';"
|
||||
;;
|
||||
search)
|
||||
stmt="SELECT COUNT(*) FROM search_history WHERE anime_name = '$2';"
|
||||
;;
|
||||
watch | sync)
|
||||
stmt="SELECT COUNT(*) FROM watch_history WHERE anime_name = '$2' AND episode_number = '$3';"
|
||||
;;
|
||||
anime)
|
||||
stmt="SELECT COUNT(*) FROM anime WHERE anime_name = '$2';"
|
||||
;;
|
||||
esac
|
||||
res=$(run_stmt "$stmt")
|
||||
return "$res"
|
||||
}
|
||||
|
||||
# return true (0) if $source_dt > $target_dt
|
||||
check_date() {
|
||||
source_dt="$1"
|
||||
target_dt="$2"
|
||||
if [[ "$source_dt" < "$target_dt" ]] || [[ "$source_dt" == "$target_dt" ]]; then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# updates search/watch date for passed in anime
|
||||
update_date() {
|
||||
datetime=$(date +'%Y-%m-%d %H:%M:%S')
|
||||
stmt=""
|
||||
case "$1" in
|
||||
directory)
|
||||
stmt="UPDATE file_history SET watch_date = '$datetime' WHERE directory = '$2' and filename = 'DIRECTORY';"
|
||||
;;
|
||||
file)
|
||||
stmt="UPDATE file_history SET watch_date = '$datetime' WHERE directory = '$2' and filename = '$3';"
|
||||
;;
|
||||
search)
|
||||
stmt="UPDATE search_history SET search_date = '$datetime' WHERE anime_name = '$2';"
|
||||
;;
|
||||
sync)
|
||||
temp_dt="${3// /:}"
|
||||
[ -z "$temp_dt" ] && return 1
|
||||
hist_dt=$(run_stmt "SELECT watch_date FROM watch_history WHERE anime_name='$2' AND episode_number='$3';")
|
||||
hist_dt="${hist_dt// /:}"
|
||||
if ! check_date "$hist_dt" "$temp_dt"; then
|
||||
lg "Passed in date is older or same than current date... doing nothing"
|
||||
return 1
|
||||
fi
|
||||
stmt="UPDATE watch_history SET watch_date = '$temp_dt' WHERE anime_name = '$2' AND episode_number = $3;"
|
||||
;;
|
||||
watch)
|
||||
stmt="UPDATE watch_history SET watch_date = '$datetime' WHERE anime_name = '$2' AND episode_number = $3;"
|
||||
;;
|
||||
anime)
|
||||
return
|
||||
;;
|
||||
esac
|
||||
lg "UPDATE STMT -> $stmt"
|
||||
run_stmt "$stmt"
|
||||
}
|
||||
|
||||
# inserts into search/watch history db
|
||||
# check the anime_name/id
|
||||
insert_history() {
|
||||
datetime=$(date +'%Y-%m-%d %H:%M:%S')
|
||||
lg "Checking if ($*) exists in db"
|
||||
if ! check_db "$@"; then
|
||||
lg "Match found... Updating row in history db..."
|
||||
update_date "$@"
|
||||
res=$?
|
||||
else
|
||||
lg "Row not found in DB... inserting"
|
||||
case "$1" in
|
||||
directory)
|
||||
stmt="INSERT INTO file_history(directory, filename, watch_date) VALUES('$2', 'DIRECTORY', '$datetime');"
|
||||
;;
|
||||
file)
|
||||
stmt="INSERT INTO file_history(directory, filename, watch_date) VALUES('$2', '$3', '$datetime');"
|
||||
;;
|
||||
search)
|
||||
stmt="INSERT INTO search_history(anime_name, search_date) VALUES('$2', '$datetime');"
|
||||
;;
|
||||
watch)
|
||||
stmt="INSERT INTO watch_history(anime_name, episode_number, watch_date) VALUES('$2', '$3', '$datetime');"
|
||||
;;
|
||||
sync)
|
||||
stmt="INSERT INTO watch_history(anime_name, episode_number, watch_date) VALUES('$2', '$3', '$4');"
|
||||
;;
|
||||
anime)
|
||||
stmt="INSERT INTO anime(anime_name, start_episode, end_episode, data_date) VALUES('$2', $3, $4, '$datetime');"
|
||||
;;
|
||||
esac
|
||||
lg "INSERT STATEMENT -> $stmt"
|
||||
run_stmt "$stmt"
|
||||
res=$?
|
||||
fi
|
||||
return $res
|
||||
}
|
||||
|
||||
sync_search_history() {
|
||||
cnt=0
|
||||
errs=0
|
||||
while read -r line; do
|
||||
anime_name=$(awk -F '|' '{print $2}' <<< "$line")
|
||||
if sqlite3 -noheader "$HISTORY_DB" "SELECT COUNT(*) FROM search_history WHERE anime_name = '$anime_name'"; then
|
||||
search_date=$(awk -F '|' '{print $3}' <<< "$line")
|
||||
if ! sqlite3 "$HISTORY_DB" "INSERT INTO search_history(anime_name, search_date) VALUES('$anime_name', '$search_date')"; then
|
||||
((++errs))
|
||||
continue
|
||||
fi
|
||||
((++cnt))
|
||||
fi
|
||||
done < <(sqlite3 -list -noheader "$temp_db" "SELECT * FROM search_history")
|
||||
lg "$cnt rows inserted into search_history table"
|
||||
lg "$errs errors on insert"
|
||||
}
|
||||
|
||||
sync_watch_history() {
|
||||
cnt=0
|
||||
errs=0
|
||||
while read -r line; do
|
||||
anime_name="${line/ //}"
|
||||
while read -r ep; do
|
||||
episode_num=$(awk -F '|' '{print $1}' <<< "$ep")
|
||||
watch_date=$(awk -F '|' '{print $NF}' <<< "$ep")
|
||||
if ! insert_history "sync" "$anime_name" "$episode_num" "$watch_date"; then
|
||||
((++errs))
|
||||
continue
|
||||
fi
|
||||
((++cnt))
|
||||
done < <(sqlite3 -list -noheader "$temp_db" "SELECT episode_number, watch_date FROM watch_history WHERE anime_name = '$anime_name'")
|
||||
done < <(sqlite3 -list -noheader "$temp_db" "SELECT anime_name FROM watch_history")
|
||||
lg "$cnt rows inserted into watch_history table"
|
||||
lg "$errs rows skipped on insert"
|
||||
}
|
||||
|
||||
# vim: ft=sh
|
47
setup.sh
47
setup.sh
@ -7,7 +7,7 @@
|
||||
######################
|
||||
VERBOSE=0
|
||||
|
||||
log() {
|
||||
lg() {
|
||||
if [[ "$VERBOSE" -eq 1 ]]; then
|
||||
printf "%s\n" "$*"
|
||||
fi
|
||||
@ -16,7 +16,7 @@ log() {
|
||||
if [[ $# -ge 1 ]]; then
|
||||
if [[ "$1" == "-v" || "$1" == "--verbose" ]]; then
|
||||
VERBOSE=1
|
||||
log "VERBOSE LOGGING ENABLED"
|
||||
lg "VERBOSE lgGING ENABLED"
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -25,8 +25,8 @@ DB="history.sqlite3"
|
||||
DIR="${XDG_CONFIG_HOME:-$HOME/.config}/aniwrapper"
|
||||
MPV_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/mpv"
|
||||
|
||||
log "CONFIG DIR:" "$DIR"
|
||||
log "MPV DIR:" "$MPV_DIR"
|
||||
lg "CONFIG DIR:" "$DIR"
|
||||
lg "MPV DIR:" "$MPV_DIR"
|
||||
|
||||
# executes aniwrapper setup
|
||||
# 1. create the aniwrapper directory in $XDG_CONFIG_HOME
|
||||
@ -35,47 +35,48 @@ log "MPV DIR:" "$MPV_DIR"
|
||||
# 4. move skip-intro.lua into mpv/scripts folder
|
||||
# 5. move the aniwrapper icon to $XDG_CONFIG_HOME/aniwrapper/ directory
|
||||
run_setup() {
|
||||
log "INSTALL DIR: $DIR"
|
||||
lg "INSTALL DIR: $DIR"
|
||||
|
||||
if [[ ! -d "$DIR" ]]; then
|
||||
log "Creating directory $DIR"
|
||||
lg "Creating directory $DIR"
|
||||
mkdir -p "$DIR"
|
||||
log "Directory created"
|
||||
lg "Directory created"
|
||||
fi
|
||||
|
||||
if [[ ! -f "$DIR/$DB" ]]; then
|
||||
log "CREATING HISTORY DATABASE"
|
||||
sqlite3 "$DIR/$DB" < sql/search_history_tbl.sql
|
||||
sqlite3 "$DIR/$DB" < sql/watch_history_tbl.sql
|
||||
sqlite3 "$DIR/$DB" < sql/file_history.sql
|
||||
log "FINISHED CREATING DB"
|
||||
fi
|
||||
lg "CREATING HISTORY DATABASE IF NOT EXISTS"
|
||||
sqlite3 "$DIR/$DB" < sql/history.sql
|
||||
lg "FINISHED CREATING DB"
|
||||
|
||||
# log "themes directory does not exist in filesystem... Creating and moving themes"
|
||||
lg "INSTALLING UI FILES TO $DIR/lib/ani-cli"
|
||||
mkdir -p "$DIR/lib/ani-cli"
|
||||
cp -r lib/ani-cli/* "$DIR/lib/ani-cli/"
|
||||
lg "FINISHED INSTALLING UI FILES"
|
||||
|
||||
# lg "themes directory does not exist in filesystem... Creating and moving themes"
|
||||
mkdir -p "$DIR/themes"
|
||||
cp themes/* "$DIR/themes/"
|
||||
log "Theme files moved..."
|
||||
lg "Theme files moved..."
|
||||
|
||||
log "Creating mpv/scripts/ directory if it doesn't exist..."
|
||||
lg "Creating mpv/scripts/ directory if it doesn't exist..."
|
||||
mkdir -p "$MPV_DIR/scripts/"
|
||||
if [[ ! -f "$MPV_DIR/scripts/skip-intro.lua" ]]; then
|
||||
log "Moving skip-intro.lua into mpv scripts directory..."
|
||||
lg "Moving skip-intro.lua into mpv scripts directory..."
|
||||
cp lua/skip-intro.lua "$MPV_DIR/scripts/"
|
||||
log "Moved skip-intro.lua into scripts directory..."
|
||||
lg "Moved skip-intro.lua into scripts directory..."
|
||||
else
|
||||
log "skip-intro.lua already exists in $XDG_CONFIG_HOME/mpv/scripts/... skipping"
|
||||
lg "skip-intro.lua already exists in $XDG_CONFIG_HOME/mpv/scripts/... skipping"
|
||||
fi
|
||||
|
||||
if [[ ! -d "$DIR/icons" ]]; then
|
||||
log "Creating icons directory"
|
||||
lg "Creating icons directory"
|
||||
mkdir -p "$DIR/icons"
|
||||
fi
|
||||
cp .assets/icons/* "$DIR/icons/"
|
||||
log "Installed icons in config directory..."
|
||||
lg "Installed icons in config directory..."
|
||||
}
|
||||
|
||||
if run_setup; then
|
||||
log "Setup Complete...."
|
||||
lg "Setup Complete...."
|
||||
else
|
||||
printf "%s\n" "There was an error during setup"
|
||||
exit 1
|
||||
|
@ -1,12 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS file_history (
|
||||
id integer PRIMARY KEY AUTOINCREMENT,
|
||||
directory varchar(200) NOT NULL,
|
||||
filename varchar(200) NOT NULL,
|
||||
watch_date DATETIME NOT NULL,
|
||||
CHECK (LENGTH(directory) > 0),
|
||||
CHECK (LENGTH(filename) > 0),
|
||||
UNIQUE (directory, filename)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS dir_filename_idx ON file_history (directory, filename);
|
||||
|
39
sql/history.sql
Normal file
39
sql/history.sql
Normal file
@ -0,0 +1,39 @@
|
||||
CREATE TABLE IF NOT EXISTS anime (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
anime_name VARCHAR(255) NOT NULL UNIQUE,
|
||||
start_episode INTEGER NOT NULL,
|
||||
end_episode INTEGER NOT NULL,
|
||||
data_date DATETIME NOT NULL,
|
||||
CHECK(start_episode <= end_episode),
|
||||
CHECK(LENGTH(anime_name) > 0)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS file_history (
|
||||
id integer PRIMARY KEY AUTOINCREMENT,
|
||||
directory varchar(200) NOT NULL,
|
||||
filename varchar(200) NOT NULL,
|
||||
watch_date DATETIME NOT NULL,
|
||||
CHECK (LENGTH(directory) > 0),
|
||||
CHECK (LENGTH(filename) > 0),
|
||||
UNIQUE (directory, filename)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS watch_history (
|
||||
id integer PRIMARY KEY AUTOINCREMENT,
|
||||
anime_name varchar(200) NOT NULL,
|
||||
episode_number integer NOT NULL,
|
||||
watch_date DATETIME NOT NULL,
|
||||
CHECK (LENGTH(anime_name) > 0),
|
||||
UNIQUE (anime_name, episode_number)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS search_history (
|
||||
id integer PRIMARY KEY AUTOINCREMENT,
|
||||
anime_name varchar(200) NOT NULL UNIQUE,
|
||||
search_date DATETIME NOT NULL,
|
||||
CHECK (LENGTH(anime_name) > 0)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS anime_search_idx ON search_history (anime_name);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS watch_anime_episode_idx ON watch_history (anime_name, episode_number);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS dir_filename_idx ON file_history (directory, filename);
|
@ -1,9 +0,0 @@
|
||||
CREATE TABLE search_history (
|
||||
id integer PRIMARY KEY AUTOINCREMENT,
|
||||
anime_name varchar(200) NOT NULL UNIQUE,
|
||||
search_date DATETIME NOT NULL,
|
||||
CHECK (LENGTH(anime_name) > 0)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX anime_search_idx ON search_history (anime_name, search_date);
|
||||
|
@ -1,12 +0,0 @@
|
||||
CREATE TABLE watch_history (
|
||||
id integer PRIMARY KEY AUTOINCREMENT,
|
||||
anime_name varchar(200) NOT NULL,
|
||||
episode_number integer NOT NULL,
|
||||
watch_date DATETIME NOT NULL,
|
||||
CHECK (LENGTH(anime_name) > 0),
|
||||
CHECK (episode_number > 0),
|
||||
UNIQUE (anime_name, episode_number, watch_date)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS watch_anime_episode_idx ON watch_history (anime_name, episode_number);
|
||||
|
196
themes/aniwrapper-alter.rasi
Normal file
196
themes/aniwrapper-alter.rasi
Normal file
@ -0,0 +1,196 @@
|
||||
/*******************************************************************************
|
||||
* ROFI Color Theme
|
||||
* User: Sheepla, sudacode
|
||||
* Copyleft: Sheepla
|
||||
*******************************************************************************/
|
||||
|
||||
* {
|
||||
highlight: bold italic;
|
||||
scrollbar: true;
|
||||
|
||||
palette-bg0: #2E333E;
|
||||
palette-bg1: #404552;
|
||||
palette-fg0: #c6c8d1;
|
||||
palette-highlight: #6552ab;
|
||||
palette-active: #525AAB;
|
||||
palette-warning: #B65FB8;
|
||||
|
||||
/* Base colors */
|
||||
background: @palette-bg0;
|
||||
background-color: @background;
|
||||
foreground: @palette-fg0;
|
||||
|
||||
/* Normal colors */
|
||||
normal-background: @background;
|
||||
normal-foreground: @foreground;
|
||||
alternate-normal-background: @palette-bg1;
|
||||
alternate-normal-foreground: @foreground;
|
||||
selected-normal-background: @palette-highlight;
|
||||
selected-normal-foreground: @palette-fg0;
|
||||
|
||||
/* Active window colors */
|
||||
active-background: @palette-active;
|
||||
active-foreground: @normal-foreground;
|
||||
alternate-active-background: @alternate-normal-background;
|
||||
alternate-active-foreground: @active-foreground;
|
||||
selected-active-background: @active-background;
|
||||
selected-active-foreground: @active-foreground;
|
||||
|
||||
/* Urgent colors */
|
||||
urgent-background: @background;
|
||||
urgent-foreground: @palette-warning;
|
||||
alternate-urgent-background: @alternate-normal-background;
|
||||
alternate-urgent-foreground: @urgent-foreground;
|
||||
selected-urgent-background: @urgent-foreground;
|
||||
selected-urgent-foreground: @normal-background;
|
||||
|
||||
/* Other colors */
|
||||
border-color: @palette-highlight;
|
||||
separatorcolor: @border-color;
|
||||
scrollbar-handle: @palette-highlight;
|
||||
}
|
||||
|
||||
window {
|
||||
background-color: @background-color;
|
||||
children: [mainbox];
|
||||
width: 80%;
|
||||
anchor: center;
|
||||
location: center;
|
||||
}
|
||||
|
||||
mainbox {
|
||||
border: 0;
|
||||
orientation: vertical;
|
||||
children: [ entry, message, listview, mode-switcher ];
|
||||
}
|
||||
|
||||
entry {
|
||||
expand: false;
|
||||
text-color: @normal-foreground;
|
||||
/* Padding between 2 lines */
|
||||
padding: 10px 0px 10px 10px;
|
||||
border: 0 0 2px;
|
||||
border-color: @palette-highlight;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
sidebar {
|
||||
expand: false;
|
||||
}
|
||||
|
||||
/* Message box */
|
||||
textbox {
|
||||
horizontal-align: 0;
|
||||
background-color: @palette-highlight;
|
||||
padding: 10px 20px 10px 20px;
|
||||
text-color: @palette-fg0;
|
||||
}
|
||||
|
||||
listview {
|
||||
border: 0px 0px 0px ;
|
||||
border-color: @palette-highlight;
|
||||
padding: 0px 0px 5px 0px;
|
||||
scrollbar: @scrollbar;
|
||||
lines: 12;
|
||||
columns: 2;
|
||||
}
|
||||
|
||||
|
||||
mode-switcher {
|
||||
border: 3px 0px 0px 0px;
|
||||
border-color: @palette-highlight;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#button.selected {
|
||||
background-color: @selected-normal-background;
|
||||
text-color: @selected-normal-foreground;
|
||||
}
|
||||
|
||||
#element {
|
||||
border: 0;
|
||||
padding: 3px 10px 3px 10px ;
|
||||
}
|
||||
|
||||
element.normal.normal {
|
||||
background-color: @normal-background;
|
||||
text-color: @normal-foreground;
|
||||
}
|
||||
|
||||
element.normal.urgent {
|
||||
background-color: @urgent-background;
|
||||
text-color: @urgent-foreground;
|
||||
}
|
||||
|
||||
element.normal.active {
|
||||
background-color: @active-background;
|
||||
text-color: @active-foreground;
|
||||
}
|
||||
|
||||
element.selected.normal {
|
||||
background-color: @selected-normal-background;
|
||||
text-color: @selected-normal-foreground;
|
||||
}
|
||||
|
||||
element.selected.urgent {
|
||||
background-color: @selected-urgent-background;
|
||||
text-color: @selected-urgent-foreground;
|
||||
}
|
||||
|
||||
element.selected.active {
|
||||
background-color: @palette-highlight;
|
||||
text-color: @alternate-active-foreground;
|
||||
}
|
||||
|
||||
element.alternate.normal {
|
||||
background-color: @normal-background;
|
||||
text-color: @normal-foreground;
|
||||
}
|
||||
|
||||
element.alternate.urgent {
|
||||
background-color: @urgent-background;
|
||||
text-color: @urgent-foreground;
|
||||
}
|
||||
|
||||
element.alternate.active {
|
||||
background-color: @active-background;
|
||||
text-color: @active-foreground;
|
||||
}
|
||||
|
||||
inputbar {
|
||||
spacing: 0;
|
||||
text-color: @normal-foreground;
|
||||
padding: 2px;
|
||||
children: [ textbox-prompt-sep, entry, case-indicator ];
|
||||
}
|
||||
|
||||
case-indicator,
|
||||
entry,
|
||||
button {
|
||||
spacing: 0;
|
||||
text-color: @normal-foreground;
|
||||
}
|
||||
|
||||
button.selected {
|
||||
background-color: @selected-normal-background;
|
||||
text-color: @selected-normal-foreground;
|
||||
}
|
||||
|
||||
textbox-prompt-sep {
|
||||
expand: false;
|
||||
str: ":";
|
||||
text-color: @normal-foreground;
|
||||
margin: 0 0.3em 0 0;
|
||||
}
|
||||
|
||||
prompt {
|
||||
padding:6px 9px;
|
||||
background-color: @palette-highlight;
|
||||
}
|
||||
|
||||
element-icon {
|
||||
size: 18;
|
||||
}
|
@ -1,141 +0,0 @@
|
||||
/**
|
||||
* User: keystroke3
|
||||
* Copyright: keystroke3
|
||||
*
|
||||
*/
|
||||
|
||||
configuration {
|
||||
sidebar-mode: false;
|
||||
font: "Open Sans 12";
|
||||
}
|
||||
|
||||
* {
|
||||
text-color: @foreground;
|
||||
active-background: rgb(170, 70, 104);
|
||||
active-foreground: @foreground;
|
||||
normal-background: @background;
|
||||
normal-foreground: @foreground;
|
||||
urgent-background: #9E2A5E;
|
||||
urgent-foreground: @foreground;
|
||||
alternate-active-background: @background;
|
||||
alternate-active-foreground: @foreground;
|
||||
alternate-normal-background: @background;
|
||||
alternate-normal-foreground: @foreground;
|
||||
alternate-urgent-background: @background;
|
||||
alternate-urgent-foreground: @foreground;
|
||||
selected-active-background: #9E2A5E;
|
||||
selected-active-foreground: @foreground;
|
||||
selected-normal-background: rgb(170, 70, 104);
|
||||
selected-normal-foreground: #0c0816;
|
||||
selected-urgent-background: #9D596B;
|
||||
selected-urgent-foreground: @foreground;
|
||||
background-color: #0c0816;
|
||||
background: #D03C6E30;
|
||||
foreground: #8fc5c6;
|
||||
spacing: 0;
|
||||
}
|
||||
|
||||
window {
|
||||
location: west;
|
||||
anchor: west;
|
||||
height: 70%;
|
||||
width: 25%;
|
||||
orientation: vertical;
|
||||
children: [mainbox];
|
||||
border: 2px 2px 2px 0px;
|
||||
border-color: @active-background;
|
||||
hide-scrollbar: true;
|
||||
}
|
||||
|
||||
mainbox {
|
||||
spacing: 0.2em;
|
||||
children: [inputbar, listview];
|
||||
}
|
||||
|
||||
|
||||
|
||||
listview {
|
||||
spacing: 0.6em;
|
||||
dynamic: false;
|
||||
cycle: true;
|
||||
padding: 0px 5px 0px 5px;
|
||||
}
|
||||
|
||||
inputbar {
|
||||
border-radius: 50%;
|
||||
padding: 5px;
|
||||
border-spacing: 5px 0 0 0;
|
||||
border: 1px;
|
||||
spacing: 10px;
|
||||
margin: 5px 0 10px;
|
||||
border-color: @foreground;
|
||||
|
||||
}
|
||||
|
||||
entry{
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
|
||||
prompt{
|
||||
padding: 5px;
|
||||
background-color: @foreground;
|
||||
text-color: @background-color;
|
||||
border: 1px;
|
||||
border-radius: 50%;
|
||||
|
||||
}
|
||||
|
||||
|
||||
element {
|
||||
padding: 10px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
element normal.normal {
|
||||
background-color: @normal-background;
|
||||
text-color: @normal-foreground;
|
||||
}
|
||||
|
||||
element normal.urgent {
|
||||
background-color: @urgent-background;
|
||||
text-color: @urgent-foreground;
|
||||
}
|
||||
|
||||
element normal.active {
|
||||
background-color: #0390fc;
|
||||
text-color: @active-foreground;
|
||||
}
|
||||
|
||||
element selected.normal {
|
||||
background-color: @selected-normal-background;
|
||||
text-color: @selected-normal-foreground;
|
||||
border-color: @active-background;
|
||||
}
|
||||
|
||||
element selected.urgent {
|
||||
background-color: @selected-urgent-background;
|
||||
text-color: @selected-urgent-foreground;
|
||||
}
|
||||
|
||||
element selected.active {
|
||||
background-color: @selected-normal-background;
|
||||
text-color: #0390fc;
|
||||
/* text-color: @selected-active-foreground; */
|
||||
}
|
||||
|
||||
element alternate.normal {
|
||||
background-color: @normal-background;
|
||||
text-color: @normal-foreground;
|
||||
}
|
||||
|
||||
element alternate.urgent {
|
||||
background-color: @urgent-background;
|
||||
text-color: @urgent-foreground;
|
||||
}
|
||||
|
||||
element alternate.active {
|
||||
/* background-color: @active-background; */
|
||||
background-color: #0390fc;
|
||||
text-color: @active-foreground;
|
||||
}
|
147
themes/aniwrapper-monokai.rasi
Normal file
147
themes/aniwrapper-monokai.rasi
Normal file
@ -0,0 +1,147 @@
|
||||
/**
|
||||
* ROFI Color theme
|
||||
* User: milouse, sudacode
|
||||
* Copyright: Étienne Deparis
|
||||
*/
|
||||
|
||||
* {
|
||||
selected-normal-foreground: rgba ( 248, 248, 242, 100 % );
|
||||
foreground: rgba ( 248, 248, 242, 100 % );
|
||||
normal-foreground: @foreground;
|
||||
alternate-normal-background: rgba ( 39, 40, 34, 0 % );
|
||||
red: rgba ( 220, 50, 47, 100 % );
|
||||
selected-urgent-foreground: rgba ( 248, 248, 242, 100 % );
|
||||
blue: rgba ( 38, 139, 210, 100 % );
|
||||
urgent-foreground: rgba ( 249, 38, 114, 100 % );
|
||||
alternate-urgent-background: rgba ( 39, 40, 34, 0 % );
|
||||
/* active-foreground: rgba ( 166, 226, 42, 100 % ); */
|
||||
active-foreground: @blue;
|
||||
lightbg: rgba ( 238, 232, 213, 100 % );
|
||||
selected-active-foreground: rgba ( 166, 226, 42, 100 % );
|
||||
alternate-active-background: rgba ( 39, 40, 34, 0 % );
|
||||
background: rgba ( 39, 40, 34, 93 % );
|
||||
bordercolor: rgba ( 0, 43, 54, 100 % );
|
||||
alternate-normal-foreground: @foreground;
|
||||
normal-background: rgba ( 39, 40, 34, 0 % );
|
||||
lightfg: rgba ( 88, 104, 117, 100 % );
|
||||
selected-normal-background: rgba ( 20, 20, 17, 100 % );
|
||||
border-color: @foreground;
|
||||
spacing: 2;
|
||||
separatorcolor: rgba ( 230, 219, 116, 100 % );
|
||||
urgent-background: rgba ( 39, 40, 34, 0 % );
|
||||
selected-urgent-background: rgba ( 249, 38, 114, 100 % );
|
||||
alternate-urgent-foreground: @urgent-foreground;
|
||||
background-color: rgba ( 0, 0, 0, 0 % );
|
||||
alternate-active-foreground: @active-foreground;
|
||||
active-background: rgba ( 39, 40, 34, 0 % );
|
||||
selected-active-background: rgba ( 20, 20, 17, 100 % );
|
||||
}
|
||||
window {
|
||||
background-color: @background;
|
||||
border: 1;
|
||||
padding: 5;
|
||||
}
|
||||
mainbox {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
message {
|
||||
border: 2px 0px 0px ;
|
||||
border-color: @separatorcolor;
|
||||
padding: 1px ;
|
||||
}
|
||||
textbox {
|
||||
text-color: @foreground;
|
||||
}
|
||||
listview {
|
||||
fixed-height: 0;
|
||||
border: 2px 0px 0px ;
|
||||
border-color: @separatorcolor;
|
||||
spacing: 2px ;
|
||||
scrollbar: true;
|
||||
padding: 2px 0px 0px ;
|
||||
}
|
||||
element {
|
||||
border: 0;
|
||||
padding: 1px ;
|
||||
}
|
||||
element-text {
|
||||
background-color: inherit;
|
||||
text-color: inherit;
|
||||
}
|
||||
element.normal.normal {
|
||||
background-color: @normal-background;
|
||||
text-color: @normal-foreground;
|
||||
}
|
||||
element.normal.urgent {
|
||||
background-color: @urgent-background;
|
||||
text-color: @urgent-foreground;
|
||||
}
|
||||
element.normal.active {
|
||||
background-color: @active-background;
|
||||
text-color: @active-foreground;
|
||||
}
|
||||
element.selected.normal {
|
||||
background-color: @selected-normal-background;
|
||||
text-color: @selected-normal-foreground;
|
||||
}
|
||||
element.selected.urgent {
|
||||
background-color: @selected-urgent-background;
|
||||
text-color: @selected-urgent-foreground;
|
||||
}
|
||||
element.selected.active {
|
||||
background-color: @selected-active-background;
|
||||
text-color: @selected-active-foreground;
|
||||
}
|
||||
element.alternate.normal {
|
||||
background-color: @alternate-normal-background;
|
||||
text-color: @alternate-normal-foreground;
|
||||
}
|
||||
element.alternate.urgent {
|
||||
background-color: @alternate-urgent-background;
|
||||
text-color: @alternate-urgent-foreground;
|
||||
}
|
||||
element.alternate.active {
|
||||
background-color: @alternate-active-background;
|
||||
text-color: @alternate-active-foreground;
|
||||
}
|
||||
scrollbar {
|
||||
width: 4px ;
|
||||
border: 0;
|
||||
handle-width: 8px ;
|
||||
padding: 0;
|
||||
}
|
||||
mode-switcher {
|
||||
border: 2px 0px 0px ;
|
||||
border-color: @separatorcolor;
|
||||
}
|
||||
button.selected {
|
||||
background-color: @selected-normal-background;
|
||||
text-color: @selected-normal-foreground;
|
||||
}
|
||||
inputbar {
|
||||
spacing: 0;
|
||||
text-color: @normal-foreground;
|
||||
padding: 1px ;
|
||||
}
|
||||
case-indicator {
|
||||
spacing: 0;
|
||||
text-color: @normal-foreground;
|
||||
}
|
||||
entry {
|
||||
spacing: 0;
|
||||
text-color: @normal-foreground;
|
||||
}
|
||||
prompt {
|
||||
spacing: 0;
|
||||
text-color: @normal-foreground;
|
||||
}
|
||||
inputbar {
|
||||
children: [ prompt,textbox-prompt-colon,entry,case-indicator ];
|
||||
}
|
||||
textbox-prompt-colon {
|
||||
expand: false;
|
||||
str: ":";
|
||||
margin: 0px 0.3em 0em 0em ;
|
||||
text-color: @normal-foreground;
|
||||
}
|
113
themes/aniwrapper-nord2.rasi
Normal file
113
themes/aniwrapper-nord2.rasi
Normal file
@ -0,0 +1,113 @@
|
||||
/*******************************************************************************
|
||||
* ROUNDED THEME FOR ROFI
|
||||
* User : LR-Tech
|
||||
* Theme Repo : https://github.com/lr-tech/rofi-themes-collection
|
||||
*******************************************************************************/
|
||||
|
||||
* {
|
||||
font: "Roboto 12";
|
||||
|
||||
background-color: transparent;
|
||||
text-color: @fg0;
|
||||
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
spacing: 0px;
|
||||
bg0: #2E3440F2;
|
||||
bg1: #3B4252;
|
||||
bg2: #4C566A80;
|
||||
bg3: #88C0D0F2;
|
||||
fg0: #D8DEE9;
|
||||
fg1: #ECEFF4;
|
||||
fg2: #D8DEE9;
|
||||
fg3: #4C566A;
|
||||
}
|
||||
|
||||
window {
|
||||
location: center;
|
||||
width: 80%;
|
||||
border-radius: 24px;
|
||||
background-color: @bg0;
|
||||
anchor: center;
|
||||
}
|
||||
|
||||
mainbox {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
inputbar {
|
||||
background-color: @bg1;
|
||||
border-color: @bg3;
|
||||
|
||||
border: 2px;
|
||||
border-radius: 16px;
|
||||
|
||||
padding: 8px 16px;
|
||||
spacing: 8px;
|
||||
children: [ prompt, entry, case-indicator ];
|
||||
}
|
||||
|
||||
prompt {
|
||||
text-color: @fg2;
|
||||
}
|
||||
|
||||
entry {
|
||||
placeholder: "Search";
|
||||
placeholder-color: @fg3;
|
||||
text-color: @fg0;
|
||||
}
|
||||
|
||||
case-indicator {
|
||||
spacing: 0;
|
||||
text-color: @bg3;
|
||||
}
|
||||
|
||||
message {
|
||||
margin: 12px 0 0;
|
||||
border-radius: 16px;
|
||||
border-color: @bg2;
|
||||
background-color: @bg2;
|
||||
}
|
||||
|
||||
textbox {
|
||||
padding: 8px 24px;
|
||||
}
|
||||
|
||||
listview {
|
||||
background-color: transparent;
|
||||
|
||||
margin: 12px 0 0;
|
||||
lines: 12;
|
||||
columns: 2;
|
||||
|
||||
fixed-height: false;
|
||||
scrollbar: false;
|
||||
}
|
||||
|
||||
element {
|
||||
padding: 8px 16px;
|
||||
spacing: 8px;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
|
||||
element normal active, element alternate active {
|
||||
background-color: @bg3;
|
||||
}
|
||||
|
||||
element selected normal, element selected active {
|
||||
background-color: @bg3;
|
||||
text-color: @bg1;
|
||||
}
|
||||
|
||||
element-icon {
|
||||
size: 1em;
|
||||
vertical-align: 0.5;
|
||||
}
|
||||
|
||||
element-text {
|
||||
text-color: inherit;
|
||||
}
|
||||
element selected {
|
||||
text-color: @bg1;
|
||||
}
|
@ -86,16 +86,17 @@ listview {
|
||||
margin: 0px 0px 1px 0px;
|
||||
}
|
||||
element {
|
||||
border: 2px;
|
||||
border: 3px;
|
||||
border-color: #d19a66;
|
||||
padding: 2px 15px;
|
||||
padding: 3px 15px;
|
||||
margin: 1px;
|
||||
}
|
||||
element-text {
|
||||
background-color: inherit;
|
||||
text-color: inherit;
|
||||
}
|
||||
element.normal.normal {
|
||||
background-color: @normal-background;
|
||||
background-color: @alternate-normal-background;
|
||||
text-color: @normal-foreground;
|
||||
}
|
||||
element.normal.urgent {
|
||||
@ -103,7 +104,7 @@ element.normal.urgent {
|
||||
text-color: @urgent-foreground;
|
||||
}
|
||||
element.normal.active {
|
||||
background-color: @active-background;
|
||||
background-color: @alternate-normal-background;
|
||||
border-color: @blue;
|
||||
text-color: @blue;
|
||||
}
|
||||
@ -184,7 +185,7 @@ prompt {
|
||||
|
||||
inputbar {
|
||||
children: [ prompt,textbox-prompt-colon,entry,case-indicator ];
|
||||
padding: 15px 0px;
|
||||
padding: 1px 0px;
|
||||
}
|
||||
|
||||
textbox-prompt-colon {
|
||||
|
Reference in New Issue
Block a user