flix_fs/scanner/
library.rs

1//! The library scanner will scan an entire directory using the generic
2//! scanner
3
4use std::ffi::OsStr;
5use std::path::Path;
6
7use async_stream::stream;
8use tokio::fs;
9use tokio_stream::Stream;
10use tokio_stream::wrappers::ReadDirStream;
11
12use crate::Error;
13use crate::scanner::generic;
14
15/// A library item
16pub type Item = crate::Item<generic::Scanner>;
17
18/// The scanner for collections
19pub enum Scanner {}
20
21impl Scanner {
22	/// Scan a folder for a library
23	pub fn scan_library(path: &Path) -> impl Stream<Item = Item> {
24		stream!({
25			let dirs = match fs::read_dir(path).await {
26				Ok(dirs) => dirs,
27				Err(err) => {
28					yield Item {
29						path: path.to_owned(),
30						event: Err(Error::ReadDir(err)),
31					};
32					return;
33				}
34			};
35
36			let mut subdirs_to_scan = Vec::new();
37
38			for await dir in ReadDirStream::new(dirs) {
39				match dir {
40					Ok(dir) => {
41						let filetype = match dir.file_type().await {
42							Ok(filetype) => filetype,
43							Err(err) => {
44								yield Item {
45									path: path.to_owned(),
46									event: Err(Error::FileType(err)),
47								};
48								continue;
49							}
50						};
51
52						let path = dir.path();
53						if filetype.is_dir() {
54							subdirs_to_scan.push(path);
55							continue;
56						}
57
58						match path.extension().and_then(OsStr::to_str) {
59							Some(_) | None => {
60								yield Item {
61									path: path.to_owned(),
62									event: Err(Error::UnexpectedFile),
63								};
64							}
65						}
66					}
67					Err(err) => {
68						yield Item {
69							path: path.to_owned(),
70							event: Err(Error::ReadDirEntry(err)),
71						}
72					}
73				}
74			}
75
76			for subdir in subdirs_to_scan {
77				for await event in generic::Scanner::scan_detect_folder(&subdir, None) {
78					yield event;
79				}
80			}
81		})
82	}
83}