Compare commits

..

137 Commits

Author SHA1 Message Date
211850c85f New encryption (#21)
* new encryption for animixplay direct links

fix increment char for uppercase letters

* apply fixes
2022-11-14 22:07:14 -08:00
06d3ad3ff2 update provider ordering 2022-10-21 22:46:12 -07:00
3117738f27 update highlighting and play first episode automatically (#20) 2022-10-13 22:07:24 -07:00
64d70c34f2 update gogoanime url 2022-10-13 17:47:42 -07:00
d9d7549553 Fix menu showing after completing download(s) 2022-10-08 13:54:00 -07:00
5804f84f83 fix streaming menu (#19) 2022-10-06 20:41:15 -07:00
fd954e7ede Add episode selection param (#18)
* fix quality selection

* add episode selection argument

* fix quality selection menu appearing when flag not set

* fix episode selection appearing when no episodes released yet

* update readme

* update readme

* make selected quality the default if watching/downloading multiple episodes
2022-10-06 20:17:48 -07:00
da45bf15fe fix ordering of declarations 2022-09-13 17:56:45 -07:00
b3f1dea8ab update providers (#16)
* update providers list and fix mp4 quality selection

* cleanup code and update download function

* update scraping logic
2022-09-10 11:17:00 -07:00
2c7789c58f fix duplicate search results (#15) 2022-07-29 22:53:56 -07:00
2bab68a887 add menu and option for selecting provider to scrape (#14) 2022-07-19 00:10:38 -07:00
df82425eae update readme images 2022-07-14 00:02:08 -07:00
b92dd11fe6 move play from file and db functions into own files (#13)
* move play from file and db functions into own files
2022-07-13 23:40:19 -07:00
c384c93147 switch to axel instead of aria2c (#12) 2022-07-11 16:52:30 -07:00
fa108d860f fix multiword searches from menu (#11) 2022-07-11 12:30:27 -07:00
1c8afc16cc fix infinite loop on no results found 2022-07-10 05:26:30 -07:00
e8054c6cf2 update table definitions 2022-06-27 00:41:04 -07:00
bd949bb7c7 update to v3 functions (#8)
* update to v3 functions

* fix progress prompt appearing in rofi menus

* modularize UI in ani-cli for rofi vs cli
2022-06-26 21:38:28 -07:00
737d54bcd2 fix episode selection menu on anime with 0- episodes 2022-06-25 16:55:25 -07:00
7d574f7a6f fix theme not being passed properly in all cases 2022-06-16 23:35:35 -07:00
7ad12b0da8 squash more bugs 2022-06-12 21:51:53 -07:00
c7911dc0a7 squash some bugs 2022-06-12 21:33:12 -07:00
92b10cc0f6 update readme 2022-06-12 21:20:15 -07:00
e9c2048076 update readme 2022-06-12 19:18:38 -07:00
acdcf05514 cleanup code 2022-06-12 19:02:15 -07:00
ec41f5abb3 fix parsing of autoplay and silent mode flags 2022-06-12 19:00:03 -07:00
af7dee7d85 update cli flag parsing and cleanup code 2022-06-12 18:52:26 -07:00
822e40074c revert changes 2022-06-12 18:36:30 -07:00
80682a26db update cli flag parsing and cleanup code 2022-06-12 18:29:35 -07:00
4828923abb Add option to browse recently updated anime (#6)
* add recently updated anime option

* update aniwrapper menu ordering and increase columns to 2

* replace hardcoded base_url with variable
2022-06-12 00:00:37 -07:00
ba6c302022 Merge pull request #5 from ksyasuda/autoplay
add autoplay
2022-06-04 20:37:21 -07:00
f218b34e21 make autoplay stop after last episode 2022-06-04 16:37:55 -07:00
e5772469c7 update docs 2022-06-04 16:24:06 -07:00
2e53ac3bfc cleanup code 2022-06-04 16:24:02 -07:00
8d6acddea6 make yes default option autoplay prompt 2022-06-04 14:26:36 -07:00
870920cbf5 move anime_id from prompt to message in rofi prompt 2022-06-04 14:13:24 -07:00
1b797bee3e add autoplay flag for continue watching prompt after each episode 2022-06-04 02:05:37 -07:00
692301d893 add disclaimer 2022-05-18 22:23:32 -07:00
77eaa9e4b0 implement log access time fix 2022-05-05 16:59:27 -07:00
ce83a6155b fix same episode playing 2022-05-03 20:36:02 -07:00
73e6b8d181 add alternate link feature from main script 2022-05-02 17:19:05 -07:00
6dd2b4c279 update watch history highlighting when there is an episode 0 2022-04-25 19:49:05 -07:00
04476f3ba4 allow autoselecting episode 0 2022-04-25 19:39:22 -07:00
d061438e2e allow episode 0 2022-04-25 19:30:38 -07:00
505e5125b9 update link parsing 2022-04-19 13:01:47 -07:00
9322d028f8 Merge branch 'master' of github.com:ksyasuda/aniwrapper 2022-04-18 09:44:59 -07:00
0892bb1845 fix decryption alg again 2022-04-18 09:42:00 -07:00
ae0c19b5f2 add m3u8 quality parsing and fix mp4 quality parsing 2022-04-17 18:43:14 -07:00
13635cabf2 update decryption alg 2022-04-17 18:13:40 -07:00
d7e78836a4 add dynamic keys parsing code from main script 2022-04-15 22:18:18 -07:00
7c8a13573b new encryption keys 2022-04-15 04:36:43 -07:00
2f0f552068 update keys 2022-04-14 08:40:45 -07:00
47f9ca19ae refactor stream function to match check_db return code 2022-04-08 00:54:20 -07:00
acb236ce23 auto select episode if only one exists 2022-04-07 01:18:46 -07:00
fd59f7e2fe fix downloading an episode from menu 2022-04-03 13:43:09 -07:00
925b7c86e2 fix no search results found loop if no query provided 2022-04-03 11:59:16 -07:00
aa821e774a update readme 2022-04-02 16:27:51 -07:00
73eb2a274e implement some ani-cli V2 functions 2022-04-02 14:36:39 -07:00
6af4a46b86 clean up code a bit 2022-03-31 20:04:07 -07:00
cee96ec9cc monkey see monkey do 2022-03-29 17:45:32 -07:00
1d1dc517f4 fix episode naming for m3u8 download 2022-03-27 23:37:09 -07:00
0ea84fb450 fix episode naming for aria2c download 2022-03-26 11:56:37 -07:00
8327afc43e add ffmpeg as dependency 2022-03-15 16:41:01 -07:00
c7fb101b10 add ffmpeg for m3u8 download and update cryptography 2022-03-15 15:09:50 -07:00
228c2014c7 remove support for mplayer 2022-03-03 23:54:59 -08:00
006fdc6572 update episode selection prompt in command line mode 2022-03-03 23:46:52 -08:00
3c4189e3ac add resume function to command-line download mode 2022-03-03 23:42:48 -08:00
5c7093daf0 fix bug in interactive mode 2022-03-03 23:35:47 -08:00
776c4961aa update help/docs 2022-03-03 18:57:18 -08:00
aac3761e37 add -r flag to select previously watched anime and start at ep selection 2022-03-03 18:53:23 -08:00
aa39625956 port over new decrypt function to fix scraping issue 2022-03-03 18:04:20 -08:00
4af41db0bf add openssl to dep_ch function 2022-02-22 08:30:57 -08:00
8882405c0e add option to download current episode 2022-02-22 08:18:14 -08:00
4d704d4b32 make queries not distinct since uniqueness is enforced at table level 2022-02-21 19:41:50 -08:00
7a3a61bb58 run insert queries in background before search_eps function 2022-02-20 20:00:25 -08:00
f95ae51af8 check exit code directly in update_date function 2022-02-20 19:57:40 -08:00
8fb570b003 simplify logic in find_media function 2022-02-20 19:11:14 -08:00
d7bd5899b5 revert change for now so new episodes can be picked up 2022-02-20 17:47:16 -08:00
924b0eed76 update watch history when downloading anime 2022-02-20 15:36:34 -08:00
74ac27bb79 update link parsing 2022-02-19 22:14:01 -08:00
7c85a91d65 spaces -> tabs 2022-02-19 22:13:07 -08:00
e851b92289 add new themes to selection menu 2022-02-19 02:36:02 -08:00
04cad2425b fix selecting new anime 2022-02-19 02:10:05 -08:00
d390d0a683 update manpage 2022-02-19 01:36:37 -08:00
3bfbaa7749 add anime lookup table for tracking start/end episodes for each anime/season 2022-02-19 01:35:41 -08:00
6137deb26b consolidate sql scripts into one 2022-02-19 01:33:02 -08:00
a56fe29a29 add anime table and consolidate into one script 2022-02-19 01:32:33 -08:00
f23586116d add alter and monokai theme 2022-02-18 12:18:28 -08:00
6e5b3c463a fix script not quitting when escaping from play from file mode 2022-02-16 23:58:20 -08:00
01fe1bb68a apply autoformatter to markdown files 2022-02-16 23:57:43 -08:00
02349915c1 sort directory list in play from file mode 2022-02-16 00:43:40 -08:00
1461c3bc62 change -only-match to -no-custom to allow ESC to quit rofi menus 2022-02-15 02:22:59 -08:00
4c2d7ae27e window titles for rofi 2022-02-15 02:20:10 -08:00
d2611e6e33 fix updating datetime and enforce list mode on sqlite3 2022-02-15 01:26:19 -08:00
41c40bbd38 add dir history to play from file menu 2022-02-15 01:25:24 -08:00
90dec870e0 less hardcoding in theme selection and row highlighting 2022-02-13 12:06:06 -08:00
e29d3f7db3 update base_url to new site 2022-02-13 00:16:27 -08:00
7907e809b8 make menus have active entry selected by default 2022-02-11 17:50:46 -08:00
7a0eea5d69 make quality highlighting more dynamic 2022-02-11 17:41:31 -08:00
f1fbb643aa update showcase image 2022-02-10 01:54:38 -08:00
8895ab9145 update showcase 2022-02-10 01:53:54 -08:00
9f80566b6e change continue to use search history so sorting works as intended 2022-02-09 20:52:54 -08:00
024bb138f0 Merge branch 'master' of github.com:ksyasuda/aniwrapper 2022-02-09 20:23:22 -08:00
3b5511cfb4 add 480p quality 2022-02-09 20:22:54 -08:00
3647be366f remove flamingo theme and add nord2 2022-02-09 19:50:26 -08:00
260d212e22 update readme 2022-02-08 19:32:30 -08:00
cc9d66d4a2 update showcase 2022-02-08 19:10:42 -08:00
eb0677fef3 add showcase video to readme 2022-02-08 18:40:47 -08:00
2221d550c0 remove whitespace from ep number if coming from continue function 2022-02-08 18:27:16 -08:00
86a4e187a6 improvements 2022-02-08 00:12:43 -08:00
fa958884bb convert tabs to spaces 2022-02-07 12:06:31 -08:00
b272fc3994 make videos open in background in play from file 2022-02-07 03:20:29 -08:00
c6d5c6a1bd make logging statements use inf function 2022-02-07 02:09:23 -08:00
593b66edea remove support for playing mp3 files in play from file 2022-02-07 02:09:09 -08:00
cdfe2674d7 port over the new ani-cli command-line menu code 2022-02-07 01:40:40 -08:00
7d08c212fa update error handling for episode selection 2022-02-06 21:08:27 -08:00
10a675202a update docs/help to reflect latest changes 2022-02-06 20:06:30 -08:00
c3b0a26ce7 update script to allow player selection in command-line mode 2022-02-06 20:04:37 -08:00
49cf4f3ecc update readme and manpage to reflect latest changes 2022-02-06 19:43:24 -08:00
86acb7d731 fix help section of readme 2022-02-06 00:16:12 -08:00
1268855077 update readme 2022-02-05 23:54:26 -08:00
087fb9d355 update readme 2022-02-05 23:13:44 -08:00
42db51371b update manpage 2022-02-05 23:06:01 -08:00
5c7af5c36d add ability to supply player function (mpv/mplayer/vlc fully supported) 2022-02-05 16:46:12 -08:00
cf7cf4b591 update sizing of sync menus 2022-02-05 14:35:24 -08:00
1fddd452fe update sizing of reselect quality menu 2022-02-05 14:27:29 -08:00
5aad3a7263 update episode selection menu width 2022-02-05 14:24:09 -08:00
a6e80c1ad0 update default flamingo width to work with new menu sizings 2022-02-05 14:23:54 -08:00
c5bf198466 update sizing of rofi menus 2022-02-05 14:20:05 -08:00
1a54bf3b44 update default theme 2022-02-05 14:19:29 -08:00
0d97d3857a update readme 2022-02-05 00:46:27 -08:00
280bd73760 fix images 2022-02-05 00:38:00 -08:00
c18cb37f71 fix image link 2022-02-05 00:26:34 -08:00
9cb0075cd1 fix indentation on help message 2022-02-05 00:24:24 -08:00
0ba2ebac2c fix spelling 2022-02-05 00:21:39 -08:00
2d7ed5dce0 update readme 2022-02-05 00:18:42 -08:00
14dee88f11 add manpage 2022-02-04 22:54:16 -08:00
23 changed files with 2399 additions and 1287 deletions

BIN
.assets/showcase.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

View File

@ -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
View File

@ -4,7 +4,7 @@
[**_Setup_**](#setup) | [**_Usage_**](#usage) | [**_Screenshots_**](#screenshots)
![Aniwrapper screenshot](https://imgur.com/HFq5gCq.png)
[![click to view showcase](.assets/showcase.jpg)](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
![selection with dash](https://imgur.com/vSyaoG6.png)
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">
![example](https://imgur.com/itdGCsI.gif)
</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">
![example](https://imgur.com/d23iYy7.gif)
</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">
![example](https://thumbor.sudacode.com/svHFsX6ti3HZey32mX8uvEAjsLs=/600x0/smart/https%3A%2F%2Fthumbor.sudacode.com%2Fimage%2F395af378c5c44e0c9d45b0a44ea072ed%2Faniwrapper-recently-updated)
</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
![aniwrapper main menu](https://imgur.com/HFq5gCq.png)
![aniwrapper main menu](https://thumbor.sudacode.com/cQTsFEWsSDLk4uxDXDEzLZ6iz5A=/800x0/smart/https%3A%2F%2Flychee.sudacode.com%2Fuploads%2Fbig%2Fe88fd7df7ccb5f626ee8200491034ae1.png)
| | |
| :---------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------: |
| <details><summary>doom-one</summary> ![doomone](https://imgur.com/zMU0i8l.png) </details> | <details><summary>dracula</summary> ![dracula](https://imgur.com/BPdIuX3.png)</details> |
| <details><summary>fancy</summary>![fancy](https://imgur.com/CZx73NL.png)</details> | <details><summary>material</summary>![material](https://imgur.com/eTWkxw2.png)</details> |
| <details><summary>onedark</summary>![onedark](https://imgur.com/rchqtBm.png)</details> | <details><summary>flamingo (sidebar theme)</summary>![flamingo-theme](https://imgur.com/pxF7hRE.png)</details> |
| | |
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| <details><summary>alter</summary> ![alter](https://thumbor.sudacode.com/0tuoFHdJSX-ngb1821RITEAd_CQ=/800x0/smart/https%3A%2F%2Flychee.sudacode.com%2Fuploads%2Fbig%2Feb491f4d017fff38e52adcc0549ae6df.png) </details> | <details><summary>aniwrapper</summary> ![aniwrapper](https://thumbor.sudacode.com/cQTsFEWsSDLk4uxDXDEzLZ6iz5A=/800x0/smart/https%3A%2F%2Flychee.sudacode.com%2Fuploads%2Fbig%2Fe88fd7df7ccb5f626ee8200491034ae1.png) </details> |
| <details><summary>doom-one</summary> ![doomone](https://thumbor.sudacode.com/6BI7O7v9wR6ALeE4wL9uL26peT0=/800x0/smart/https%3A%2F%2Flychee.sudacode.com%2Fuploads%2Fbig%2F7d496a3208c892717c99be5bc1c84105.png) </details> | <details><summary>dracula</summary> ![dracula](https://thumbor.sudacode.com/L9R0wutce1Le5euJ0oinduMaXo4=/800x0/smart/https%3A%2F%2Flychee.sudacode.com%2Fuploads%2Fbig%2F9b8b8cc5e4cde8f76c39e4ab83cda6a3.png)</details> |
| <details><summary>fancy</summary>![fancy](https://thumbor.sudacode.com/mv1t2d3dPyRTwc1IIajoHZq6vnI=/800x0/smart/https%3A%2F%2Flychee.sudacode.com%2Fuploads%2Fbig%2Fd12f56fd513c5083f8e7316145ad5436.png)</details> | <details><summary>material</summary>![material](https://thumbor.sudacode.com/oOR41ZN6Cguch5oU2f9zDtdFyZc=/800x0/smart/https%3A%2F%2Flychee.sudacode.com%2Fuploads%2Fbig%2F40a1f13fc77b4ae8b75b082268e10391.png)</details> |
| <details><summary>monokai</summary>![monokai](https://thumbor.sudacode.com/ff1i68B4KlWsbVuN0s11eL_SXBI=/800x0/smart/https%3A%2F%2Flychee.sudacode.com%2Fuploads%2Fbig%2Fd9e8cec045948a2c32c9c7126da86294.png)</details> | <details><summary>nord</summary>![nord](https://thumbor.sudacode.com/l6wzDKIHbTpURbTX414BscTGlGg=/800x0/smart/https%3A%2F%2Flychee.sudacode.com%2Fuploads%2Fbig%2F636fbfea8aa40f10a9dd4d592015c58a.png)</details> |
| <details><summary>nord2</summary>![nord2](https://thumbor.sudacode.com/TTeXKVJpU75rT0Xe5Towmroc6Eo=/800x0/smart/https%3A%2F%2Flychee.sudacode.com%2Fuploads%2Fbig%2Fc358c9ca95aacb05bfad69b6b175db0c.png)</details> | <details><summary>onedark</summary>![onedark](https://thumbor.sudacode.com/ta8X8qGjH9to-_6-IDHHrOFpysM=/800x0/smart/https%3A%2F%2Flychee.sudacode.com%2Fuploads%2Fbig%2Fa1801ece1de4b981e68aaeca7a9b93f7.png)</details> |
</div>

1204
ani-cli

File diff suppressed because it is too large Load Diff

View File

@ -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
View 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
View File

@ -0,0 +1,60 @@
# Search Anime
<div align="center">
![search anime menu](https://imgur.com/i5uJIug.png)
</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">
![select anime menu](https://imgur.com/HIWAg6d.png)
</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">
![episode selection menu](https://imgur.com/bI4pz5V.png)
</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">
![play from file 1](https://imgur.com/Xkrdi7a.png)
![play from file 2](https://imgur.com/btHUxUl.png)
</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">
![choose theme menu](https://imgur.com/qUQDj5g.png)
</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
View 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
View 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
View 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
View 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
View 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
View 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

View File

@ -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

View File

@ -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
View 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);

View File

@ -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);

View File

@ -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);

View 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;
}

View File

@ -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;
}

View 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;
}

View 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;
}

View File

@ -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 {