mirror of
https://github.com/SinTan1729/movie-rename.git
synced 2025-04-18 09:57:41 -05:00
Compare commits
34 commits
Author | SHA1 | Date | |
---|---|---|---|
49de0ce13c | |||
cd0dbcd47b | |||
3757dd0a47 | |||
cf8a9ee764 | |||
80fdc110ae | |||
c5b1f51233 | |||
|
3e7b8fbd5d | ||
|
f979559b50 | ||
443c8e6cc9 | |||
4f3f349292 | |||
51e0c84eb4 | |||
83bf1f7af6 | |||
b4073357f7 | |||
67dcd9e378 | |||
b62bffd340 | |||
|
4a69071380 | ||
|
6027b701f0 | ||
1b43b7a017 | |||
|
bc2c9c0135 | ||
|
324cae4fed | ||
64d1749450 | |||
bc0ccd8107 | |||
16118a8d5a | |||
790ec225ea | |||
|
e74c35472a | ||
|
0a851a47fd | ||
c2152264f9 | |||
|
3695c78282 | ||
|
f827e351c3 | ||
39835837c4 | |||
a2f0536642 | |||
fd98c5d355 | |||
cc59a03051 | |||
89d15e9fb7 |
10 changed files with 1356 additions and 529 deletions
1580
Cargo.lock
generated
1580
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
14
Cargo.toml
14
Cargo.toml
|
@ -1,6 +1,7 @@
|
|||
[package]
|
||||
name = "movie-rename"
|
||||
version = "2.1.2"
|
||||
version = "2.3.2"
|
||||
build = "build.rs"
|
||||
edition = "2021"
|
||||
authors = ["Sayantan Santra <sayantan[dot]santra689[at]gmail[dot]com"]
|
||||
license = "GPL-3.0"
|
||||
|
@ -16,10 +17,15 @@ categories = ["command-line-utilities"]
|
|||
|
||||
[dependencies]
|
||||
torrent-name-parser = "0.12.1"
|
||||
tmdb-api = "0.4.0"
|
||||
inquire = "0.6.2"
|
||||
tmdb-api = "0.8.0"
|
||||
inquire = "0.7.5"
|
||||
load_file = "1.0.1"
|
||||
tokio = { version = "1.28.1", features = ["macros", "rt-multi-thread"] }
|
||||
tokio = { version = "1.32.0", features = ["macros", "rt-multi-thread"] }
|
||||
clap = { version = "4.5.1", features = ["cargo"] }
|
||||
|
||||
[build-dependencies]
|
||||
clap = { version = "4.5.1", features = ["cargo"] }
|
||||
clap_complete = "4.5.1"
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
|
|
4
Makefile
4
Makefile
|
@ -2,7 +2,7 @@ PREFIX := /usr/local
|
|||
PKGNAME := movie-rename
|
||||
|
||||
build:
|
||||
cargo build --release
|
||||
cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.34
|
||||
|
||||
build-debug:
|
||||
cargo build
|
||||
|
@ -19,6 +19,6 @@ uninstall:
|
|||
rm -f "$(DESTDIR)$(PREFIX)/man/man1/$(PKGNAME).1"
|
||||
|
||||
aur: build
|
||||
tar --transform 's/.*\///g' -czf $(PKGNAME).tar.gz target/release/$(PKGNAME) $(PKGNAME).1
|
||||
tar --transform 's/.*\///g' -czf $(PKGNAME).tar.gz target/x86_64-unknown-linux-gnu/release/$(PKGNAME) target/autocomplete/* $(PKGNAME).1
|
||||
|
||||
.PHONY: build build-debug install clean uninstall aur
|
||||
|
|
|
@ -30,7 +30,8 @@ sudo make install
|
|||
- Default pattern is `{title} ({year}) - {director}`. Extension is always kept.
|
||||
- Passing `--directory` or `-d` assumes that the arguments are directory names, which contain exactly one movie and optionally subtitles.
|
||||
- Passing `--dry-run` or `-n` does a dry tun and only prints out the new names, without actually doing anything.
|
||||
- Passing `-nd` or `-dn` does a dry run in directory mode.
|
||||
- Passing `--i-feel-lucky` or `-l` automatically chooses the first option. Useful when you use the program as part of a script.
|
||||
- You can join the short flags `-d`, `-n` and `-l` together (e.g. `-dn` or `-dln`).
|
||||
- Passing `--help` or `-h` shows help and exits.
|
||||
- Passing `--version` or `-v` shows version and exits.
|
||||
|
||||
|
|
21
build.rs
Normal file
21
build.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
use clap_complete::generate_to;
|
||||
use clap_complete::shells::{Bash, Fish, Zsh};
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::{create_dir, remove_dir_all};
|
||||
use std::io::Error;
|
||||
|
||||
include!("src/args.rs");
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
let target = "./target/autocomplete";
|
||||
remove_dir_all(target).ok();
|
||||
create_dir(target)?;
|
||||
let outdir = OsString::from(target);
|
||||
|
||||
let mut cmd = get_command();
|
||||
generate_to(Bash, &mut cmd, "movie-rename", &outdir)?;
|
||||
generate_to(Fish, &mut cmd, "movie-rename", &outdir)?;
|
||||
generate_to(Zsh, &mut cmd, "movie-rename", &outdir)?;
|
||||
Ok(())
|
||||
}
|
|
@ -17,9 +17,6 @@ Performs a dry run, without actually renaming anything.
|
|||
-d, --directory
|
||||
Runs in directory mode. In this mode, it is assumed that the arguments are directory names, which contain exactly one movie and optionally subtitles.
|
||||
.TP
|
||||
-dn, -nd
|
||||
Performs a dry run in directory mode.
|
||||
.TP
|
||||
-h, --help
|
||||
Print help information.
|
||||
.TP
|
||||
|
|
46
src/args.rs
Normal file
46
src/args.rs
Normal file
|
@ -0,0 +1,46 @@
|
|||
use clap::{arg, command, ArgAction, Command, ValueHint};
|
||||
use std::collections::HashMap;
|
||||
|
||||
// Bare command generation function to help with autocompletion
|
||||
pub fn get_command() -> Command {
|
||||
command!()
|
||||
.name("movie-rename")
|
||||
.author("Sayantan Santra <sayantan.santra@gmail.com>")
|
||||
.about("A simple tool to rename movies, written in Rust.")
|
||||
.arg(arg!(-d --directory "Run in directory mode").action(ArgAction::SetTrue))
|
||||
.arg(arg!(-n --"dry-run" "Do a dry run").action(ArgAction::SetTrue))
|
||||
.arg(arg!(-l --"i-feel-lucky" "Always choose the first option").action(ArgAction::SetTrue))
|
||||
.arg(
|
||||
arg!([entries] "The files/directories to be processed")
|
||||
.trailing_var_arg(true)
|
||||
.num_args(1..)
|
||||
.value_hint(ValueHint::AnyPath)
|
||||
.required(true),
|
||||
)
|
||||
// Use -v instead of -V for version
|
||||
.disable_version_flag(true)
|
||||
.arg(arg!(-v --version "Print version").action(ArgAction::Version))
|
||||
.arg_required_else_help(true)
|
||||
}
|
||||
|
||||
// Function to process the passed arguments
|
||||
pub fn process_args() -> (Vec<String>, HashMap<String, bool>) {
|
||||
let matches = get_command().get_matches();
|
||||
|
||||
// Generate the settings HashMap from read flags
|
||||
let mut settings = HashMap::new();
|
||||
for id in matches.ids().map(|x| x.as_str()) {
|
||||
if id != "entries" {
|
||||
settings.insert(id.to_string(), matches.get_flag(id));
|
||||
}
|
||||
}
|
||||
|
||||
// Every unmatched argument should be treated as a file entry
|
||||
let entries: Vec<String> = matches
|
||||
.get_many::<String>("entries")
|
||||
.expect("No entries provided!")
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
(entries, settings)
|
||||
}
|
111
src/functions.rs
111
src/functions.rs
|
@ -2,25 +2,23 @@ use inquire::{
|
|||
ui::{Color, IndexPrefix, RenderConfig, Styled},
|
||||
InquireError, Select,
|
||||
};
|
||||
use std::{collections::HashMap, fs, path::Path, process::exit};
|
||||
use std::{collections::HashMap, fs, path::Path};
|
||||
use tmdb_api::{
|
||||
client::{reqwest::ReqwestExecutor, Client},
|
||||
movie::{credits::MovieCredits, search::MovieSearch},
|
||||
prelude::Command,
|
||||
Client,
|
||||
};
|
||||
use torrent_name_parser::Metadata;
|
||||
|
||||
use crate::structs::{get_long_lang, Language, MovieEntry};
|
||||
|
||||
// Get the version from Cargo.toml
|
||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
// Function to process movie entries
|
||||
pub async fn process_file(
|
||||
filename: &String,
|
||||
tmdb: &Client,
|
||||
tmdb: &Client<ReqwestExecutor>,
|
||||
pattern: &str,
|
||||
dry_run: bool,
|
||||
lucky: bool,
|
||||
movie_list: Option<&HashMap<String, Option<String>>>,
|
||||
// The last bool tells whether the entry should be added to the movie_list or not
|
||||
// The first String is filename without extension, and the second String is
|
||||
|
@ -129,22 +127,28 @@ pub async fn process_file(
|
|||
return (filename_without_ext, None, true);
|
||||
}
|
||||
|
||||
// Choose from the possible entries
|
||||
let choice = match Select::new(
|
||||
format!(" Possible choices for {file_base}:").as_str(),
|
||||
movie_list,
|
||||
)
|
||||
.prompt()
|
||||
{
|
||||
Ok(movie) => movie,
|
||||
Err(error) => {
|
||||
println!(" {error}");
|
||||
let flag = matches!(
|
||||
error,
|
||||
InquireError::OperationCanceled | InquireError::OperationInterrupted
|
||||
);
|
||||
return (filename_without_ext, None, flag);
|
||||
}
|
||||
let choice;
|
||||
if lucky {
|
||||
// Take first choice if in lucky mode
|
||||
choice = movie_list.into_iter().next().unwrap();
|
||||
} else {
|
||||
// Choose from the possible entries
|
||||
choice = match Select::new(
|
||||
format!(" Possible choices for {file_base}:").as_str(),
|
||||
movie_list,
|
||||
)
|
||||
.prompt()
|
||||
{
|
||||
Ok(movie) => movie,
|
||||
Err(error) => {
|
||||
println!(" {error}");
|
||||
let flag = matches!(
|
||||
error,
|
||||
InquireError::OperationCanceled | InquireError::OperationInterrupted
|
||||
);
|
||||
return (filename_without_ext, None, flag);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Create the new name
|
||||
|
@ -201,69 +205,8 @@ pub async fn process_file(
|
|||
(filename_without_ext, Some(new_name_base), true)
|
||||
}
|
||||
|
||||
// Function to process the passed arguments
|
||||
pub fn process_args(mut args: Vec<String>) -> (Vec<String>, HashMap<&'static str, bool>) {
|
||||
// Remove the entry corresponding to the running process
|
||||
args.remove(0);
|
||||
let mut entries = Vec::new();
|
||||
let mut settings = HashMap::from([("dry_run", false), ("directory", false)]);
|
||||
for arg in args {
|
||||
match arg.as_str() {
|
||||
"--help" | "-h" => {
|
||||
println!(" The expected syntax is:");
|
||||
println!(
|
||||
" movie-rename <filename(s)> [-n|--dry-run] [-d|--directory] [-v|--version]"
|
||||
);
|
||||
println!(
|
||||
" There needs to be a config file named config in the $XDG_CONFIG_HOME/movie-rename/ directory."
|
||||
);
|
||||
println!(" It should consist of two lines. The first line should have your TMDb API key.");
|
||||
println!(
|
||||
" The second line should have a pattern, that will be used for the rename."
|
||||
);
|
||||
println!(" In the pattern, the variables need to be enclosed in {{}}, the supported variables are `title`, `year` and `director`.");
|
||||
println!(
|
||||
" Default pattern is `{{title}} ({{year}}) - {{director}}`. Extension is always kept."
|
||||
);
|
||||
println!(" Passing --directory or -d assumes that the arguments are directory names, which contain exactly one movie and optionally subtitles.");
|
||||
println!(" Passing --dry-run or -n does a dry tun and only prints out the new names, without actually doing anything.");
|
||||
println!(" Passing -nd or -dn does a dry run in directory mode.");
|
||||
println!(" Passing --version or -v shows version and exits.");
|
||||
println!(" Pass --help to get this again.");
|
||||
exit(0);
|
||||
}
|
||||
"--version" | "-v" => {
|
||||
println!("movie-rename {VERSION}");
|
||||
exit(0);
|
||||
}
|
||||
"--dry-run" | "-n" => {
|
||||
println!("Doing a dry run...");
|
||||
settings.entry("dry_run").and_modify(|x| *x = true);
|
||||
}
|
||||
"--directory" | "-d" => {
|
||||
println!("Running in directory mode...");
|
||||
settings.entry("directory").and_modify(|x| *x = true);
|
||||
}
|
||||
"-nd" | "-dn" => {
|
||||
println!("Doing a dry run in directory mode...");
|
||||
settings.entry("dry_run").and_modify(|x| *x = true);
|
||||
settings.entry("directory").and_modify(|x| *x = true);
|
||||
}
|
||||
other => {
|
||||
if other.starts_with('-') {
|
||||
eprintln!("Unknown argument passed: {other}");
|
||||
exit(1);
|
||||
} else {
|
||||
entries.push(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(entries, settings)
|
||||
}
|
||||
|
||||
// RenderConfig for the menu items
|
||||
fn get_render_config() -> RenderConfig {
|
||||
fn get_render_config() -> RenderConfig<'static> {
|
||||
let mut render_config = RenderConfig::default();
|
||||
render_config.option_index_prefix = IndexPrefix::Simple;
|
||||
|
||||
|
|
35
src/main.rs
35
src/main.rs
|
@ -1,19 +1,31 @@
|
|||
use load_file::{self, load_str};
|
||||
use std::{collections::HashMap, env, fs, path::Path, process::exit};
|
||||
use tmdb_api::Client;
|
||||
use tmdb_api::client::{reqwest::ReqwestExecutor, Client};
|
||||
|
||||
// Import all the modules
|
||||
mod functions;
|
||||
use functions::{process_args, process_file};
|
||||
use functions::process_file;
|
||||
mod args;
|
||||
mod structs;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// Read arguments from commandline
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
||||
// Process the passed arguments
|
||||
let (entries, settings) = process_args(args);
|
||||
let (entries, settings) = args::process_args();
|
||||
let flag_dry_run = settings["dry-run"];
|
||||
let flag_directory = settings["directory"];
|
||||
let flag_lucky = settings["i-feel-lucky"];
|
||||
|
||||
// Print some message when flags are set.
|
||||
if flag_dry_run {
|
||||
println!("Doing a dry run. No files will be modified.")
|
||||
}
|
||||
if flag_directory {
|
||||
println!("Running in directory mode...")
|
||||
}
|
||||
if flag_lucky {
|
||||
println!("Automatically selecting the first entry...")
|
||||
}
|
||||
|
||||
// Try to read config file, or display error
|
||||
let mut config_file = env::var("XDG_CONFIG_HOME").unwrap_or(String::from("$HOME"));
|
||||
|
@ -38,17 +50,17 @@ async fn main() {
|
|||
}
|
||||
|
||||
// Create TMDb object for API calls
|
||||
let tmdb = Client::new(String::from(api_key));
|
||||
let tmdb = Client::<ReqwestExecutor>::new(String::from(api_key));
|
||||
|
||||
// Iterate over entries
|
||||
for entry in entries {
|
||||
// Check if the file/directory exists on disk and run necessary commands
|
||||
match settings["directory"] {
|
||||
match flag_directory {
|
||||
// Normal file
|
||||
false => {
|
||||
if Path::new(entry.as_str()).is_file() {
|
||||
// Process the filename for movie entries
|
||||
process_file(&entry, &tmdb, pattern, settings["dry_run"], None).await;
|
||||
process_file(&entry, &tmdb, pattern, flag_dry_run, flag_lucky, None).await;
|
||||
} else {
|
||||
eprintln!("The file {entry} wasn't found on disk, skipping...");
|
||||
continue;
|
||||
|
@ -69,7 +81,8 @@ async fn main() {
|
|||
&filename,
|
||||
&tmdb,
|
||||
pattern,
|
||||
settings["dry_run"],
|
||||
flag_dry_run,
|
||||
flag_lucky,
|
||||
Some(&movie_list),
|
||||
)
|
||||
.await;
|
||||
|
@ -100,7 +113,7 @@ async fn main() {
|
|||
);
|
||||
} else {
|
||||
println!("[directory] '{entry_clean}' -> '{name}'",);
|
||||
if !settings["dry_run"] {
|
||||
if !flag_dry_run {
|
||||
if !Path::new(name.as_str()).is_dir() {
|
||||
fs::rename(entry, name)
|
||||
.expect("Unable to rename directory!");
|
||||
|
|
|
@ -64,12 +64,20 @@ impl fmt::Display for MovieEntry {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut buffer = String::new();
|
||||
buffer.push_str(&format!("{} ", self.title));
|
||||
buffer.push_str(&format!("({:?}), ", self.year));
|
||||
|
||||
if let Some(year) = &self.year {
|
||||
buffer.push_str(&format!("({year}), "));
|
||||
}
|
||||
|
||||
buffer.push_str(&format!(
|
||||
"Language: {}, ",
|
||||
get_long_lang(self.language.as_str())
|
||||
));
|
||||
buffer.push_str(&format!("Directed by: {:?}, ", self.director));
|
||||
|
||||
if let Some(director) = &self.director {
|
||||
buffer.push_str(&format!("Directed by: {director}, "));
|
||||
}
|
||||
|
||||
buffer.push_str(&format!("TMDB ID: {}", self.id));
|
||||
// buffer.push_str(&format!("Synopsis: {}", self.overview));
|
||||
write!(f, "{buffer}")
|
||||
|
@ -104,18 +112,50 @@ impl fmt::Display for Language {
|
|||
|
||||
// Get long name of a language
|
||||
pub fn get_long_lang(short: &str) -> String {
|
||||
let long = match short {
|
||||
"en" => "English",
|
||||
"hi" => "Hindi",
|
||||
"bn" => "Bengali",
|
||||
"fr" => "French",
|
||||
"ja" => "Japanese",
|
||||
"de" => "German",
|
||||
"sp" => "Spanish",
|
||||
"none" => "None",
|
||||
other => other,
|
||||
};
|
||||
String::from(long)
|
||||
// List used from https://gist.github.com/carlopires/1262033/c52ef0f7ce4f58108619508308372edd8d0bd518#file-gistfile1-txt
|
||||
#[rustfmt::skip]
|
||||
static LANG_LIST: [(&str, &str); 185] = [("ab", "Abkhaz"), ("aa", "Afar"), ("af", "Afrikaans"), ("ak", "Akan"), ("sq", "Albanian"),
|
||||
("am", "Amharic"), ("ar", "Arabic"), ("an", "Aragonese"), ("hy", "Armenian"), ("as", "Assamese"), ("av", "Avaric"),
|
||||
("ae", "Avestan"), ("ay", "Aymara"), ("az", "Azerbaijani"), ("bm", "Bambara"), ("ba", "Bashkir"), ("eu", "Basque"),
|
||||
("be", "Belarusian"), ("bn", "Bengali"), ("bh", "Bihari"), ("bi", "Bislama"), ("bs", "Bosnian"), ("br", "Breton"),
|
||||
("bg", "Bulgarian"), ("my", "Burmese"), ("ca", "Catalan; Valencian"), ("ch", "Chamorro"), ("ce", "Chechen"),
|
||||
("ny", "Chichewa; Chewa; Nyanja"), ("zh", "Chinese"), ("cv", "Chuvash"), ("kw", "Cornish"), ("co", "Corsican"),
|
||||
("cr", "Cree"), ("hr", "Croatian"), ("cs", "Czech"), ("da", "Danish"), ("dv", "Divehi; Maldivian;"), ("nl", "Dutch"),
|
||||
("dz", "Dzongkha"), ("en", "English"), ("eo", "Esperanto"), ("et", "Estonian"), ("ee", "Ewe"), ("fo", "Faroese"),
|
||||
("fj", "Fijian"), ("fi", "Finnish"), ("fr", "French"), ("ff", "Fula"), ("gl", "Galician"), ("ka", "Georgian"),
|
||||
("de", "German"), ("el", "Greek, Modern"), ("gn", "Guaraní"), ("gu", "Gujarati"), ("ht", "Haitian"), ("ha", "Hausa"),
|
||||
("he", "Hebrew (modern)"), ("hz", "Herero"), ("hi", "Hindi"), ("ho", "Hiri Motu"), ("hu", "Hungarian"), ("ia", "Interlingua"),
|
||||
("id", "Indonesian"), ("ie", "Interlingue"), ("ga", "Irish"), ("ig", "Igbo"), ("ik", "Inupiaq"), ("io", "Ido"), ("is", "Icelandic"),
|
||||
("it", "Italian"), ("iu", "Inuktitut"), ("ja", "Japanese"), ("jv", "Javanese"), ("kl", "Kalaallisut"), ("kn", "Kannada"),
|
||||
("kr", "Kanuri"), ("ks", "Kashmiri"), ("kk", "Kazakh"), ("km", "Khmer"), ("ki", "Kikuyu, Gikuyu"), ("rw", "Kinyarwanda"),
|
||||
("ky", "Kirghiz, Kyrgyz"), ("kv", "Komi"), ("kg", "Kongo"), ("ko", "Korean"), ("ku", "Kurdish"), ("kj", "Kwanyama, Kuanyama"),
|
||||
("la", "Latin"), ("lb", "Luxembourgish"), ("lg", "Luganda"), ("li", "Limburgish"), ("ln", "Lingala"), ("lo", "Lao"), ("lt", "Lithuanian"),
|
||||
("lu", "Luba-Katanga"), ("lv", "Latvian"), ("gv", "Manx"), ("mk", "Macedonian"), ("mg", "Malagasy"), ("ms", "Malay"), ("ml", "Malayalam"),
|
||||
("mt", "Maltese"), ("mi", "Māori"), ("mr", "Marathi (Marāṭhī)"), ("mh", "Marshallese"), ("mn", "Mongolian"), ("na", "Nauru"),
|
||||
("nv", "Navajo, Navaho"), ("nb", "Norwegian Bokmål"), ("nd", "North Ndebele"), ("ne", "Nepali"), ("ng", "Ndonga"),
|
||||
("nn", "Norwegian Nynorsk"), ("no", "Norwegian"), ("ii", "Nuosu"), ("nr", "South Ndebele"), ("oc", "Occitan"), ("oj", "Ojibwe, Ojibwa"),
|
||||
("cu", "Old Church Slavonic"), ("om", "Oromo"), ("or", "Oriya"), ("os", "Ossetian, Ossetic"), ("pa", "Panjabi, Punjabi"), ("pi", "Pāli"),
|
||||
("fa", "Persian"), ("pl", "Polish"), ("ps", "Pashto, Pushto"), ("pt", "Portuguese"), ("qu", "Quechua"), ("rm", "Romansh"), ("rn", "Kirundi"),
|
||||
("ro", "Romanian, Moldavan"), ("ru", "Russian"), ("sa", "Sanskrit (Saṁskṛta)"), ("sc", "Sardinian"), ("sd", "Sindhi"), ("se", "Northern Sami"),
|
||||
("sm", "Samoan"), ("sg", "Sango"), ("sr", "Serbian"), ("gd", "Scottish Gaelic"), ("sn", "Shona"), ("si", "Sinhala, Sinhalese"), ("sk", "Slovak"),
|
||||
("sl", "Slovene"), ("so", "Somali"), ("st", "Southern Sotho"), ("es", "Spanish; Castilian"), ("su", "Sundanese"), ("sw", "Swahili"),
|
||||
("ss", "Swati"), ("sv", "Swedish"), ("ta", "Tamil"), ("te", "Telugu"), ("tg", "Tajik"), ("th", "Thai"), ("ti", "Tigrinya"), ("bo", "Tibetan"),
|
||||
("tk", "Turkmen"), ("tl", "Tagalog"), ("tn", "Tswana"), ("to", "Tonga"), ("tr", "Turkish"), ("ts", "Tsonga"), ("tt", "Tatar"), ("tw", "Twi"),
|
||||
("ty", "Tahitian"), ("ug", "Uighur, Uyghur"), ("uk", "Ukrainian"), ("ur", "Urdu"), ("uz", "Uzbek"), ("ve", "Venda"), ("vi", "Vietnamese"),
|
||||
("vo", "Volapük"), ("wa", "Walloon"), ("cy", "Welsh"), ("wo", "Wolof"), ("fy", "Western Frisian"), ("xh", "Xhosa"), ("yi", "Yiddish"),
|
||||
("yo", "Yoruba"), ("za", "Zhuang, Chuang"), ("zu", "Zulu"), ("none", "None")];
|
||||
|
||||
let long = LANG_LIST
|
||||
.iter()
|
||||
.filter(|x| x.0 == short)
|
||||
.map(|x| x.1)
|
||||
.next();
|
||||
|
||||
if let Some(longlang) = long {
|
||||
String::from(longlang)
|
||||
} else {
|
||||
String::from(short)
|
||||
}
|
||||
}
|
||||
|
||||
// Sanitize filename so that there are no errors while
|
||||
|
|
Loading…
Reference in a new issue