@@ -1 +1,4 @@ | |||
/target/ | |||
fakeplex/ | |||
*~ | |||
\#*\# |
@@ -0,0 +1,19 @@ | |||
[[package]] | |||
name = "booty-core" | |||
version = "0.1.0" | |||
[[package]] | |||
name = "booty-id-filebot" | |||
version = "0.1.0" | |||
dependencies = [ | |||
"booty-core 0.1.0", | |||
] | |||
[[package]] | |||
name = "bootyd" | |||
version = "0.1.0" | |||
dependencies = [ | |||
"booty-core 0.1.0", | |||
"booty-id-filebot 0.1.0", | |||
] | |||
@@ -0,0 +1,6 @@ | |||
[workspace] | |||
members = [ | |||
"bootyd", | |||
"core", | |||
"identity/filebot" | |||
] |
@@ -1,57 +1,27 @@ | |||
# Bootybot | |||
This is a script for doing things with Plex that make it easier to do other | |||
things. I'm not going to say what things those are, but we all know. | |||
The new verion of Bootybot is a daemon for managing all of your tasks on the | |||
high seas. | |||
## Dependencies | |||
**Note:** This is highly experimental and very early in development. | |||
* Filebot | |||
## Components | |||
* `unrar` | |||
### Server | |||
* Python 3 | |||
The `bootyd` program runs as a system service or in a container and should have | |||
access to all of the files you expect it to be running on. You can talk to it | |||
over a unix socket. | |||
## Configuration | |||
### CLI | |||
The default config location is `~/.config/bootybot.conf`. Below is an example. | |||
The `bootyctl` program is how you primarily interact with the running `bootyd` | |||
server to trigger content ingests and perform other administration tasks. | |||
```json | |||
{ | |||
"outdir": "/mnt/xvol1/plexdata", | |||
"extractdir": "/tmp/bootybot_extract", | |||
"simpleaction": "copy", | |||
"overrides": [ | |||
{ | |||
"name": "The Simpsons", | |||
"pattern": "The\\.Simpsons\\..*" | |||
} | |||
] | |||
} | |||
``` | |||
### Identity Engines | |||
The `outdir` property has the `{plex}` formatter from Filebot appended to it, | |||
so you should not have to worry about handling different media classes (TV, | |||
Movies, etc.). | |||
These are things for actually identifying content. | |||
The `extractdir` is where we extract data from RAR archives into. It usually | |||
ends up being emptied after we finish processing, as we move data out of here | |||
after extraction. | |||
* `filebot` - Traditional and more versatile, but not libre | |||
The `simpleaction` property is passed to Filebot when processing simple, | |||
non-archived media files. I use `copy` because of how I want to handle dealing | |||
with data *after* it's been loaded into Plex, but you might want to use `move`, | |||
`hardlink`, or `keeplink` depending on what you're situation is like. | |||
The `overrides` section is used to enforce that TV shows have their names | |||
properly auto-detected, as occasionally Filebot trips up and misses it. If none | |||
of the entries match the file then we just hope that Filebot figures it out on | |||
its own. Note that the regexes must match the *entire* filename. So it's a | |||
good idea to put a `.*` at the end to make sure it matches every file format | |||
and from any "distributor". | |||
## Usage | |||
Once you've configured it, you can just run `booty.py` in the directory of the | |||
"media" you're trying to prepare. | |||
You can set the `BOOTYCFG` envvar to override the config location. | |||
* `parley` - Bootybot's native identification engine; faster, libre, but highly experimental |
@@ -0,0 +1,16 @@ | |||
[package] | |||
name = "bootyd" | |||
version = "0.1.0" | |||
authors = ["treyzania <treyzania@gmail.com>"] | |||
[[bin]] | |||
name = "bootyd" | |||
path = "daemon.rs" | |||
[[bin]] | |||
name = "bootyctl" | |||
path = "cli.rs" | |||
[dependencies] | |||
booty-core = { path = "../core" } | |||
booty-id-filebot = { path = "../identity/filebot" } |
@@ -0,0 +1,3 @@ | |||
fn main() { | |||
println!("also not implemented yet"); | |||
} |
@@ -0,0 +1,7 @@ | |||
extern crate booty_core; | |||
extern crate booty_id_filebot; | |||
fn main() { | |||
println!("not yet implemented"); | |||
} |
@@ -0,0 +1,10 @@ | |||
[package] | |||
name = "booty-core" | |||
version = "0.1.0" | |||
authors = ["treyzania <treyzania@gmail.com>"] | |||
[lib] | |||
name = "booty_core" | |||
path = "lib.rs" | |||
[dependencies] |
@@ -0,0 +1,78 @@ | |||
/// Identifier for a particular movie or episode. Doesn't handle different | |||
/// releases of movies or anything like that. | |||
#[derive(Clone, Eq, PartialEq, Hash, Debug)] | |||
pub enum MediaId { | |||
Movie { | |||
/// Name of the movie. | |||
name: String, | |||
/// Year released, to disambiguate. | |||
year: String | |||
}, | |||
/// Episode of some TV show or anime. | |||
Episode { | |||
/// Name of the show. | |||
name: String, | |||
/// Some shows aren't released as seasons, often anime. | |||
season: Option<u32>, | |||
/// Episode with the season, or overall of no seasons. | |||
episode: u32, | |||
/// What kind of TV is it? | |||
cat: TvCategory | |||
} | |||
} | |||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] | |||
pub enum TvCategory { | |||
/// Regular TV, typically western but mostly everything else. | |||
Tv, | |||
/// Anime, which often is categorized seperately. | |||
Anime | |||
} | |||
/// Hint to provide to matching engine about content identity. | |||
#[derive(Clone, Eq, PartialEq, Hash, Debug)] | |||
pub enum IdHint { | |||
/// Name of thing, like "Inception", or "Game of Thrones". | |||
Name(String), | |||
/// Year released, usually for movies, like "2010". | |||
Year(String), | |||
/// Season of a show, like "S06". | |||
Season(String), | |||
/// Episode number, usually passed *with* a season, like "E11". | |||
Episode(String) | |||
} | |||
/// Some kind of error that can happen when trying to identify a match. | |||
#[derive(Debug)] | |||
enum MatchError { | |||
/// No matches found. | |||
NoMatches, | |||
/// Muliple matches for the file, should handle accordingly. | |||
Multiple(Vec<MediaId>), | |||
/// Error with the network. | |||
NetworkError, | |||
/// File permissions error. | |||
PermissionsError, | |||
/// In case they're using the wrong version of filebot. | |||
NonlibreError, | |||
} | |||
// TODO Decide what we want to be able to do with an engine. | |||
trait MatchinEngine { | |||
fn identify(&self, path: &Path) -> Result<MediaId, MatchError>; | |||
} |
@@ -0,0 +1,7 @@ | |||
#[cfg(test)] | |||
mod tests { | |||
#[test] | |||
fn it_works() { | |||
assert_eq!(2 + 2, 4); | |||
} | |||
} |
@@ -0,0 +1,11 @@ | |||
[package] | |||
name = "booty-id-filebot" | |||
version = "0.1.0" | |||
authors = ["treyzania <treyzania@gmail.com>"] | |||
[lib] | |||
name = "booty_id_filebot" | |||
path = "lib.rs" | |||
[dependencies] | |||
booty-core = { path = "../../core" } |
@@ -0,0 +1,9 @@ | |||
extern crate booty_core; | |||
#[cfg(test)] | |||
mod tests { | |||
#[test] | |||
fn it_works() { | |||
assert_eq!(2 + 2, 4); | |||
} | |||
} |
@@ -0,0 +1,11 @@ | |||
[package] | |||
name = "booty-id-parley" | |||
version = "0.1.0" | |||
authors = ["treyzania <treyzania@gmail.com>"] | |||
[lib] | |||
name = "booty_id_parley" | |||
path = "lib.rs" | |||
[dependencies] | |||
booty-core = { path = "../../core" } |
@@ -0,0 +1,9 @@ | |||
extern crate booty_core; | |||
#[cfg(test)] | |||
mod tests { | |||
#[test] | |||
fn it_works() { | |||
assert_eq!(2 + 2, 4); | |||
} | |||
} |
@@ -1,5 +0,0 @@ | |||
ssh_opts= | |||
ssh_prop=localhost | |||
remote_rx_dir=rx | |||
remote_mv_dir=rename | |||
@@ -1,40 +0,0 @@ | |||
#!/bin/bash | |||
MAIN_CONFIG="~/.config/bootybot/plunder.conf" | |||
if [ -f localconfig ]; then | |||
source localconfig-plunder | |||
elif [ -f "$MAIN_CONFIG" ]; then | |||
source $MAIN_CONFIG | |||
else | |||
echo 'error: no valid config found' | |||
exit 1 | |||
fi | |||
# This is from the Deluge Execute plugin. | |||
tid=$1 | |||
tname=$2 | |||
tpath=$3 | |||
######## | |||
troot="$tpath/$tid" | |||
rxpath="$remote_rx_dir/$tid" | |||
mvpath="$remote_mv_dir/$tid" | |||
function remote_exec () { | |||
ssh $ssh_opts $ssh_prop $@ | |||
} | |||
# Setup. | |||
remote_exec mkdir -p $remote_rx_dir | |||
remote_exec mkdir -p $remote_mv_dir | |||
# Actual transfer. | |||
remote_exec mkdir "$txpath" | |||
scp -r $troot $ssh_prop:"$remote_rx_dir" | |||
# Cleanup. This should be very fast. | |||
remote_exec mv "$rxpath" "$mvpath" | |||
# TODO Automaticially invoke (& fork) the rename script? | |||