6 Commits

Author SHA1 Message Date
davidskrundz 2b348851d7 Implement multiple episode numbers 2025-05-20 00:20:43 -06:00
davidskrundz 73c5e4af9b Extend model to support update command 2025-05-19 15:05:24 -06:00
davidskrundz 62e933448c Improve model 2025-05-07 20:22:05 -06:00
davidskrundz 492f054e23 Add genre strings 2025-05-04 22:30:50 -06:00
davidskrundz 343978e3f2 Strip derivable metadata 2025-05-03 18:38:53 -06:00
davidskrundz 45b0a5e601 Expose TmdbId 2025-05-03 18:08:39 -06:00
28 changed files with 505 additions and 259 deletions
Generated
+143 -121
View File
@@ -81,9 +81,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.74" version = "0.3.75"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
dependencies = [ dependencies = [
"addr2line", "addr2line",
"cfg-if", "cfg-if",
@@ -102,9 +102,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.9.0" version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
@@ -120,9 +120,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.21" version = "1.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766"
dependencies = [ dependencies = [
"shlex", "shlex",
] ]
@@ -151,9 +151,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.37" version = "4.5.38"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@@ -161,9 +161,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.5.37" version = "4.5.38"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@@ -214,7 +214,7 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]] [[package]]
name = "flix" name = "flix"
version = "0.0.1" version = "0.0.6"
dependencies = [ dependencies = [
"chrono", "chrono",
"flix-tmdb", "flix-tmdb",
@@ -224,12 +224,13 @@ dependencies = [
[[package]] [[package]]
name = "flix-cli" name = "flix-cli"
version = "0.0.1" version = "0.0.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
"flix", "flix",
"flix-tmdb", "flix-tmdb",
"futures",
"home", "home",
"serde", "serde",
"tokio", "tokio",
@@ -238,7 +239,7 @@ dependencies = [
[[package]] [[package]]
name = "flix-tmdb" name = "flix-tmdb"
version = "0.0.1" version = "0.0.6"
dependencies = [ dependencies = [
"chrono", "chrono",
"reqwest", "reqwest",
@@ -263,6 +264,20 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "futures"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.31" version = "0.3.31"
@@ -270,6 +285,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink",
] ]
[[package]] [[package]]
@@ -278,6 +294,18 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-io"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-sink"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.31" version = "0.3.31"
@@ -291,6 +319,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink",
"futures-task", "futures-task",
"pin-project-lite", "pin-project-lite",
"pin-utils", "pin-utils",
@@ -311,9 +340,9 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.3.2" version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys", "js-sys",
@@ -424,14 +453,14 @@ dependencies = [
"tokio", "tokio",
"tokio-rustls", "tokio-rustls",
"tower-service", "tower-service",
"webpki-roots", "webpki-roots 0.26.11",
] ]
[[package]] [[package]]
name = "hyper-util" name = "hyper-util"
version = "0.1.11" version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" checksum = "cf9f1e950e0d9d1d3c47184416723cf29c0d1f93bd8cccf37e4beb6b44f31710"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
@@ -449,21 +478,22 @@ dependencies = [
[[package]] [[package]]
name = "icu_collections" name = "icu_collections"
version = "1.5.0" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
dependencies = [ dependencies = [
"displaydoc", "displaydoc",
"potential_utf",
"yoke", "yoke",
"zerofrom", "zerofrom",
"zerovec", "zerovec",
] ]
[[package]] [[package]]
name = "icu_locid" name = "icu_locale_core"
version = "1.5.0" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
dependencies = [ dependencies = [
"displaydoc", "displaydoc",
"litemap", "litemap",
@@ -472,31 +502,11 @@ dependencies = [
"zerovec", "zerovec",
] ]
[[package]]
name = "icu_locid_transform"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
dependencies = [
"displaydoc",
"icu_locid",
"icu_locid_transform_data",
"icu_provider",
"tinystr",
"zerovec",
]
[[package]]
name = "icu_locid_transform_data"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d"
[[package]] [[package]]
name = "icu_normalizer" name = "icu_normalizer"
version = "1.5.0" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
dependencies = [ dependencies = [
"displaydoc", "displaydoc",
"icu_collections", "icu_collections",
@@ -504,67 +514,54 @@ dependencies = [
"icu_properties", "icu_properties",
"icu_provider", "icu_provider",
"smallvec", "smallvec",
"utf16_iter",
"utf8_iter",
"write16",
"zerovec", "zerovec",
] ]
[[package]] [[package]]
name = "icu_normalizer_data" name = "icu_normalizer_data"
version = "1.5.1" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
[[package]] [[package]]
name = "icu_properties" name = "icu_properties"
version = "1.5.1" version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
dependencies = [ dependencies = [
"displaydoc", "displaydoc",
"icu_collections", "icu_collections",
"icu_locid_transform", "icu_locale_core",
"icu_properties_data", "icu_properties_data",
"icu_provider", "icu_provider",
"tinystr", "potential_utf",
"zerotrie",
"zerovec", "zerovec",
] ]
[[package]] [[package]]
name = "icu_properties_data" name = "icu_properties_data"
version = "1.5.1" version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
[[package]] [[package]]
name = "icu_provider" name = "icu_provider"
version = "1.5.0" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
dependencies = [ dependencies = [
"displaydoc", "displaydoc",
"icu_locid", "icu_locale_core",
"icu_provider_macros",
"stable_deref_trait", "stable_deref_trait",
"tinystr", "tinystr",
"writeable", "writeable",
"yoke", "yoke",
"zerofrom", "zerofrom",
"zerotrie",
"zerovec", "zerovec",
] ]
[[package]]
name = "icu_provider_macros"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "idna" name = "idna"
version = "1.0.3" version = "1.0.3"
@@ -578,9 +575,9 @@ dependencies = [
[[package]] [[package]]
name = "idna_adapter" name = "idna_adapter"
version = "1.2.0" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
dependencies = [ dependencies = [
"icu_normalizer", "icu_normalizer",
"icu_properties", "icu_properties",
@@ -632,9 +629,9 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]] [[package]]
name = "litemap" name = "litemap"
version = "0.7.5" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
[[package]] [[package]]
name = "log" name = "log"
@@ -642,6 +639,12 @@ version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "lru-slab"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.4" version = "2.7.4"
@@ -716,6 +719,15 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "potential_utf"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
dependencies = [
"zerovec",
]
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.21" version = "0.2.21"
@@ -736,9 +748,9 @@ dependencies = [
[[package]] [[package]]
name = "quinn" name = "quinn"
version = "0.11.7" version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8"
dependencies = [ dependencies = [
"bytes", "bytes",
"cfg_aliases", "cfg_aliases",
@@ -756,12 +768,13 @@ dependencies = [
[[package]] [[package]]
name = "quinn-proto" name = "quinn-proto"
version = "0.11.11" version = "0.11.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcbafbbdbb0f638fe3f35f3c56739f77a8a1d070cb25603226c83339b391472b" checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e"
dependencies = [ dependencies = [
"bytes", "bytes",
"getrandom 0.3.2", "getrandom 0.3.3",
"lru-slab",
"rand", "rand",
"ring", "ring",
"rustc-hash", "rustc-hash",
@@ -829,7 +842,7 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [ dependencies = [
"getrandom 0.3.2", "getrandom 0.3.3",
] ]
[[package]] [[package]]
@@ -871,7 +884,7 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"web-sys", "web-sys",
"webpki-roots", "webpki-roots 0.26.11",
"windows-registry", "windows-registry",
] ]
@@ -903,9 +916,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.23.26" version = "0.23.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"ring", "ring",
@@ -926,18 +939,19 @@ dependencies = [
[[package]] [[package]]
name = "rustls-pki-types" name = "rustls-pki-types"
version = "1.11.0" version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
dependencies = [ dependencies = [
"web-time", "web-time",
"zeroize",
] ]
[[package]] [[package]]
name = "rustls-webpki" name = "rustls-webpki"
version = "0.103.1" version = "0.103.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435"
dependencies = [ dependencies = [
"ring", "ring",
"rustls-pki-types", "rustls-pki-types",
@@ -1111,9 +1125,9 @@ dependencies = [
[[package]] [[package]]
name = "tinystr" name = "tinystr"
version = "0.7.6" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
dependencies = [ dependencies = [
"displaydoc", "displaydoc",
"zerovec", "zerovec",
@@ -1136,9 +1150,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.44.2" version = "1.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes", "bytes",
@@ -1296,12 +1310,6 @@ dependencies = [
"url", "url",
] ]
[[package]]
name = "utf16_iter"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
[[package]] [[package]]
name = "utf8_iter" name = "utf8_iter"
version = "1.0.4" version = "1.0.4"
@@ -1431,9 +1439,18 @@ dependencies = [
[[package]] [[package]]
name = "webpki-roots" name = "webpki-roots"
version = "0.26.10" version = "0.26.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37493cadf42a2a939ed404698ded7fb378bf301b5011f973361779a3a74f8c93" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
dependencies = [
"webpki-roots 1.0.0",
]
[[package]]
name = "webpki-roots"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb"
dependencies = [ dependencies = [
"rustls-pki-types", "rustls-pki-types",
] ]
@@ -1457,9 +1474,9 @@ dependencies = [
[[package]] [[package]]
name = "windows-result" name = "windows-result"
version = "0.3.2" version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
dependencies = [ dependencies = [
"windows-link", "windows-link",
] ]
@@ -1621,9 +1638,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.7.9" version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@@ -1637,23 +1654,17 @@ dependencies = [
"bitflags", "bitflags",
] ]
[[package]]
name = "write16"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
[[package]] [[package]]
name = "writeable" name = "writeable"
version = "0.5.5" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
[[package]] [[package]]
name = "yoke" name = "yoke"
version = "0.7.5" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
dependencies = [ dependencies = [
"serde", "serde",
"stable_deref_trait", "stable_deref_trait",
@@ -1663,9 +1674,9 @@ dependencies = [
[[package]] [[package]]
name = "yoke-derive" name = "yoke-derive"
version = "0.7.5" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -1721,10 +1732,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
[[package]] [[package]]
name = "zerovec" name = "zerotrie"
version = "0.10.4" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
dependencies = [
"displaydoc",
"yoke",
"zerofrom",
]
[[package]]
name = "zerovec"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
dependencies = [ dependencies = [
"yoke", "yoke",
"zerofrom", "zerofrom",
@@ -1733,9 +1755,9 @@ dependencies = [
[[package]] [[package]]
name = "zerovec-derive" name = "zerovec-derive"
version = "0.10.3" version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
+3 -2
View File
@@ -34,12 +34,13 @@ overflow-checks = true
strip = "debuginfo" strip = "debuginfo"
[workspace.dependencies] [workspace.dependencies]
flix = { path = "crates/flix", version = "=0.0.1", default-features = false } flix = { path = "crates/flix", version = "=0.0.6", default-features = false }
flix-tmdb = { path = "crates/tmdb", version = "=0.0.1", default-features = false } flix-tmdb = { path = "crates/tmdb", version = "=0.0.6", default-features = false }
anyhow = { version = "^1", default-features = false } anyhow = { version = "^1", default-features = false }
chrono = { version = "^0.4", default-features = false } chrono = { version = "^0.4", default-features = false }
clap = { version = "^4", default-features = false, features = ["std"] } clap = { version = "^4", default-features = false, features = ["std"] }
futures = { version = "^0.3", default-features = false }
home = { version = "^0.5", default-features = false } home = { version = "^0.5", default-features = false }
reqwest = { version = "^0.12", default-features = false } reqwest = { version = "^0.12", default-features = false }
serde = { version = "^1", default-features = false } serde = { version = "^1", default-features = false }
+2 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "flix-cli" name = "flix-cli"
version = "0.0.1" version = "0.0.6"
categories = ["command-line-utilities"] categories = ["command-line-utilities"]
description = "CLI for interacting with flix media" description = "CLI for interacting with flix media"
@@ -48,5 +48,6 @@ clap = { workspace = true, features = [
] } ] }
home = { workspace = true } home = { workspace = true }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
futures = { workspace = true }
tokio = { workspace = true, features = ["rt", "fs", "macros"] } tokio = { workspace = true, features = ["rt", "fs", "macros"] }
toml = { workspace = true, features = ["display", "parse"] } toml = { workspace = true, features = ["display", "parse"] }
+22 -13
View File
@@ -7,9 +7,9 @@ pub mod tmdb;
#[derive(Parser)] #[derive(Parser)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
pub struct Cli { pub struct Cli {
/// Use a custom config file [default: ~/.flix] /// Use a custom config file
#[arg(short, long, value_name = "FILE")] #[arg(short, long, value_name = "FILE", default_value = "~/.flix")]
config: Option<PathBuf>, config: PathBuf,
#[command(subcommand)] #[command(subcommand)]
command: Command, command: Command,
@@ -17,17 +17,14 @@ pub struct Cli {
impl Cli { impl Cli {
pub fn config_path(&self) -> PathBuf { pub fn config_path(&self) -> PathBuf {
match self.config.as_ref() { match self.config.strip_prefix("~/") {
Some(path) => match path.strip_prefix("~/") { Ok(path) => expect_home_dir().join(path),
Ok(path) => expect_home_dir().join(path), Err(_) => self.config.to_owned(),
Err(_) => path.to_owned(),
},
None => expect_home_dir().join(".flix"),
} }
} }
pub fn command(&self) -> &Command { pub fn command(self) -> Command {
&self.command self.command
} }
} }
@@ -45,12 +42,18 @@ pub enum Command {
force: bool, force: bool,
/// Change the destination /// Change the destination
#[arg(short, long, value_name = "FILE")] #[arg(short, long, value_name = "FILE", default_value = "flix.toml")]
output: Option<PathBuf>, output: PathBuf,
#[command(subcommand)] #[command(subcommand)]
command: BackendCommand, command: BackendCommand,
}, },
/// Update a flix manifest
Update {
/// Change the destination
#[arg(short, long, value_name = "FILE", default_value = "flix.toml")]
output: PathBuf,
},
} }
#[derive(Subcommand)] #[derive(Subcommand)]
@@ -62,6 +65,12 @@ pub enum BackendCommand {
}, },
} }
impl From<tmdb::Command> for BackendCommand {
fn from(value: tmdb::Command) -> Self {
Self::Tmdb { command: value }
}
}
fn expect_home_dir() -> PathBuf { fn expect_home_dir() -> PathBuf {
#[allow(clippy::expect_used)] #[allow(clippy::expect_used)]
home::home_dir().expect("you do not have a home directory") home::home_dir().expect("you do not have a home directory")
+11 -8
View File
@@ -5,32 +5,35 @@ pub enum Command {
/// Process a TMDB collection /// Process a TMDB collection
Collection { Collection {
#[arg(value_name = "TMDB_ID")] #[arg(value_name = "TMDB_ID")]
id: i32, id: u32,
}, },
/// Process a TMDB movie /// Process a TMDB movie
Movie { Movie {
#[arg(value_name = "TMDB_ID")] #[arg(value_name = "TMDB_ID")]
id: i32, id: u32,
}, },
/// Process a TMDB show /// Process a TMDB show
Show { Show {
#[arg(value_name = "TMDB_ID")] #[arg(value_name = "TMDB_ID")]
id: i32, id: u32,
}, },
/// Process a TMDB season /// Process a TMDB season
Season { Season {
#[arg(value_name = "TMDB_ID")] #[arg(value_name = "TMDB_ID")]
id: i32, id: u32,
#[arg(value_name = "SEASON_NUM")] #[arg(value_name = "SEASON_NUM")]
season: i32, season: u32,
}, },
/// Process a TMDB episode /// Process a TMDB episode
#[command(trailing_var_arg = true)]
Episode { Episode {
#[arg(value_name = "TMDB_ID")] #[arg(value_name = "TMDB_ID")]
id: i32, id: u32,
#[arg(value_name = "SEASON_NUM")] #[arg(value_name = "SEASON_NUM")]
season: i32, season: u32,
#[arg(value_name = "EPISODE_NUM")] #[arg(value_name = "EPISODE_NUM")]
episode: i32, episode: u32,
#[arg(value_name = "...")]
episodes: Vec<u32>,
}, },
} }
+57 -31
View File
@@ -1,17 +1,20 @@
use std::path::Path;
use flix_tmdb::Client; use flix_tmdb::Client;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use clap::Parser; use clap::Parser;
use tokio::fs; use tokio::fs;
use tokio::io::AsyncWriteExt;
mod cli; mod cli;
use cli::{BackendCommand, Cli, Command}; use cli::{BackendCommand, Cli, Command};
mod config; mod config;
use config::Config; use config::Config;
use tokio::io::AsyncWriteExt;
mod run; mod run;
use run::flix::FlixObject;
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() -> Result<()> { async fn main() -> Result<()> {
@@ -25,41 +28,64 @@ async fn main() -> Result<()> {
let client = Client::new(config.tmdb().bearer_token().to_owned()); let client = Client::new(config.tmdb().bearer_token().to_owned());
match cli.command() { match cli.command() {
Command::Print { command } => match command { Command::Print { command } => exec_print(client, command).await?,
BackendCommand::Tmdb { command } => {
let object = run::tmdb::TmdbObject::fetch(&client, command).await?;
println!("{}", object.serialize().context("failed to serialize")?)
}
},
Command::Write { Command::Write {
force, force,
output, output,
command, command,
} => match command { } => exec_write(client, force, &output, command).await?,
BackendCommand::Tmdb { command } => { Command::Update { output } => exec_update(client, &output).await?,
let object = run::tmdb::TmdbObject::fetch(&client, command).await?;
let output = output
.as_ref()
.map(|p| p.as_path())
.unwrap_or(object.default_filename());
let mut file = if *force {
fs::File::create(output).await
} else {
fs::File::create_new(output).await
}
.with_context(|| format!("could not create file at path {}", output.display()))?;
file.write_all(
object
.serialize()
.context("failed to serialize tmdb object")?
.as_bytes(),
)
.await
.with_context(|| format!("could not write to file at path {}", output.display()))?;
}
},
} }
Ok(()) Ok(())
} }
async fn exec_print(client: Client, command: BackendCommand) -> Result<()> {
match command {
BackendCommand::Tmdb { command } => {
let object = run::tmdb::TmdbObject::fetch(&client, command).await?;
println!("{}", object.serialize().context("failed to serialize")?)
}
}
Ok(())
}
async fn exec_write(
client: Client,
force: bool,
output: &Path,
command: BackendCommand,
) -> Result<()> {
match command {
BackendCommand::Tmdb { command } => {
let object = run::tmdb::TmdbObject::fetch(&client, command).await?;
let mut file = if force {
fs::File::create(output).await
} else {
fs::File::create_new(output).await
}
.with_context(|| format!("could not create file at path {}", output.display()))?;
file.write_all(
object
.serialize()
.context("failed to serialize tmdb object")?
.as_bytes(),
)
.await
.with_context(|| format!("could not write to file at path {}", output.display()))?;
}
}
Ok(())
}
async fn exec_update(client: Client, output: &Path) -> Result<()> {
let content = fs::read_to_string(output)
.await
.with_context(|| format!("failed to read file at path: {}", output.display()))?;
let object: FlixObject = toml::from_str(&content)
.with_context(|| format!("failed to deserialize flix file: {}", output.display()))?;
let command = object.backend_command()?;
exec_write(client, true, output, command).await
}
+75
View File
@@ -0,0 +1,75 @@
use flix::model::{Collection, Episode, Movie, Season, Show, Verse};
use anyhow::{Result, anyhow, bail};
use crate::cli::BackendCommand;
use crate::cli::tmdb;
#[derive(Debug, serde::Deserialize)]
#[serde(untagged)]
pub enum FlixObject {
Collection(Collection),
Movie(Movie),
Show(Show),
Season(Season),
Episode(Episode),
// DEAD CODE: The TMDB backend does not support Verses
#[allow(dead_code)]
Verse(Verse),
}
impl FlixObject {
pub fn backend_command(&self) -> Result<BackendCommand> {
Ok(match self {
FlixObject::Collection(collection) => {
let Some(ref tmdb) = collection.tmdb else {
bail!("missing tmdb data")
};
tmdb::Command::Collection { id: tmdb.id.into() }.into()
}
FlixObject::Movie(movie) => {
let Some(ref tmdb) = movie.tmdb else {
bail!("missing tmdb data")
};
tmdb::Command::Movie { id: tmdb.id.into() }.into()
}
FlixObject::Show(show) => {
let Some(ref tmdb) = show.tmdb else {
bail!("missing tmdb data")
};
tmdb::Command::Show { id: tmdb.id.into() }.into()
}
FlixObject::Season(season) => {
let Some(ref tmdb) = season.tmdb else {
bail!("missing tmdb data")
};
tmdb::Command::Season {
id: tmdb.show_id.into(),
season: season.season.number,
}
.into()
}
FlixObject::Episode(episode) => {
let Some(ref tmdb) = episode.tmdb else {
bail!("missing tmdb data")
};
tmdb::Command::Episode {
id: tmdb.show_id.into(),
season: episode.episode.season,
episode: episode
.episode
.number
.primary_episode_number()
.ok_or_else(|| {
anyhow!("the episode does not have a primary episode number")
})?,
episodes: episode.episode.number.additional_episode_numbers(),
}
.into()
}
FlixObject::Verse(_) => {
bail!("verses are not handled")
}
})
}
}
+1
View File
@@ -1 +1,2 @@
pub mod flix;
pub mod tmdb; pub mod tmdb;
+59 -36
View File
@@ -1,16 +1,16 @@
use std::path::Path;
use flix::model::{ use flix::model::{
Collection, Episode, GenericCollection, GenericEpisode, GenericMovie, GenericSeason, Collection, Episode, EpisodeNumber, GenericCollection, GenericEpisode, GenericMovie,
GenericShow, Movie, Season, Show, TmdbCollection, TmdbMovie, TmdbShow, GenericSeason, GenericShow, Movie, Season, Show, TmdbCollection, TmdbEpisode, TmdbMovie,
TmdbSeason, TmdbShow,
}; };
use flix_tmdb::Client; use flix_tmdb::Client;
use flix_tmdb::model::{ use flix_tmdb::model::{
Collection as TCollection, Episode as TEpisode, Movie as TMovie, Season as TSeason, Collection as TCollection, Episode as TEpisode, Movie as TMovie, Season as TSeason,
Show as TShow, Show as TShow, ShowId,
}; };
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use futures::{StreamExt, TryStreamExt, stream};
use crate::cli::tmdb::Command; use crate::cli::tmdb::Command;
@@ -18,26 +18,16 @@ pub enum TmdbObject {
Collection(TCollection), Collection(TCollection),
Movie(TMovie), Movie(TMovie),
Show(TShow), Show(TShow),
Season(TSeason), Season(TSeason, ShowId),
Episode(TEpisode), Episode(TEpisode, Vec<u32>, u32, ShowId),
} }
impl TmdbObject { impl TmdbObject {
pub fn default_filename(&self) -> &'static Path {
Path::new(match self {
TmdbObject::Collection(_) => "collection.toml",
TmdbObject::Movie(_) => "movie.toml",
TmdbObject::Show(_) => "show.toml",
TmdbObject::Season(_) => "season.toml",
TmdbObject::Episode(_) => "episode.toml",
})
}
pub fn serialize(self) -> Result<String> { pub fn serialize(self) -> Result<String> {
Ok(match self { Ok(match self {
TmdbObject::Collection(tmdb) => toml::to_string(&Collection { TmdbObject::Collection(tmdb) => toml::to_string(&Collection {
collection: GenericCollection { collection: GenericCollection {
name: tmdb.name, title: tmdb.title,
overview: tmdb.overview, overview: tmdb.overview,
}, },
tmdb: Some(TmdbCollection { id: tmdb.id }), tmdb: Some(TmdbCollection { id: tmdb.id }),
@@ -46,18 +36,19 @@ impl TmdbObject {
movie: GenericMovie { movie: GenericMovie {
title: tmdb.title, title: tmdb.title,
overview: tmdb.overview, overview: tmdb.overview,
genres: tmdb.genres.iter().cloned().map(|g| g.name).collect(),
release_date: tmdb.release_date, release_date: tmdb.release_date,
}, },
tmdb: Some(TmdbMovie { tmdb: Some(TmdbMovie {
id: tmdb.id, id: tmdb.id,
collection: tmdb.collection.map(|c| c.id),
genres: tmdb.genres.iter().map(|g| g.id).collect(), genres: tmdb.genres.iter().map(|g| g.id).collect(),
}), }),
})?, })?,
TmdbObject::Show(tmdb) => toml::to_string(&Show { TmdbObject::Show(tmdb) => toml::to_string(&Show {
show: GenericShow { show: GenericShow {
name: tmdb.name, title: tmdb.title,
overview: tmdb.overview, overview: tmdb.overview,
genres: tmdb.genres.iter().cloned().map(|g| g.name).collect(),
air_date: tmdb.first_air_date, air_date: tmdb.first_air_date,
}, },
tmdb: Some(TmdbShow { tmdb: Some(TmdbShow {
@@ -65,29 +56,43 @@ impl TmdbObject {
genres: tmdb.genres.iter().map(|g| g.id).collect(), genres: tmdb.genres.iter().map(|g| g.id).collect(),
}), }),
})?, })?,
TmdbObject::Season(tmdb) => toml::to_string(&Season { TmdbObject::Season(tmdb, show_id) => toml::to_string(&Season {
season: GenericSeason { season: GenericSeason {
number: tmdb.season_number, number: tmdb.season_number,
name: tmdb.name, title: tmdb.title,
overview: tmdb.overview,
air_date: tmdb.air_date,
},
})?,
TmdbObject::Episode(tmdb) => toml::to_string(&Episode {
episode: GenericEpisode {
number: tmdb.episode_number,
name: tmdb.name,
overview: tmdb.overview, overview: tmdb.overview,
air_date: tmdb.air_date, air_date: tmdb.air_date,
}, },
tmdb: Some(TmdbSeason { show_id }),
})?, })?,
TmdbObject::Episode(tmdb, mut episode_numbers, season_number, show_id) => {
toml::to_string(&Episode {
episode: GenericEpisode {
number: if episode_numbers.is_empty() {
EpisodeNumber::Single {
number: tmdb.episode_number,
}
} else {
episode_numbers.insert(0, tmdb.episode_number);
EpisodeNumber::Multiple {
numbers: episode_numbers,
}
},
season: season_number,
title: tmdb.title,
overview: tmdb.overview,
air_date: tmdb.air_date,
},
tmdb: Some(TmdbEpisode { show_id }),
})?
}
}) })
} }
} }
impl TmdbObject { impl TmdbObject {
pub async fn fetch(client: &Client, command: &Command) -> Result<Self> { pub async fn fetch(client: &Client, command: Command) -> Result<Self> {
Ok(match *command { Ok(match command {
Command::Collection { id } => Self::Collection( Command::Collection { id } => Self::Collection(
client client
.collections() .collections()
@@ -115,20 +120,38 @@ impl TmdbObject {
.get_details(id, season, None) .get_details(id, season, None)
.await .await
.with_context(|| format!("could not get show details for '{id}' S{season}"))?, .with_context(|| format!("could not get show details for '{id}' S{season}"))?,
id.into(),
), ),
Command::Episode { Command::Episode {
id, id,
season, season,
episode, episode,
} => Self::Episode( episodes,
client } => {
let mut episode = client
.episodes() .episodes()
.get_details(id, season, episode, None) .get_details(id, season, episode, None)
.await .await
.with_context(|| { .with_context(|| {
format!("could not get show details for '{id}' S{season}E{episode}") format!("could not get show details for '{id}' S{season}E{episode}")
})?, })?;
), let title = stream::once(async { Ok(episode.title) })
.chain(stream::iter(episodes.clone()).then(|episode| async move {
client
.episodes()
.get_details(id, season, episode, None)
.await
.with_context(|| {
format!("could not get show details for '{id}' S{season}E{episode}")
})
.map(|episode| episode.title)
}))
.try_collect::<Vec<_>>()
.await?
.join(" + ");
episode.title = title;
Self::Episode(episode, episodes, season, id.into())
}
}) })
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "flix" name = "flix"
version = "0.0.1" version = "0.0.6"
categories = [] categories = []
description = "Types for storing persistent data about media" description = "Types for storing persistent data about media"
+2 -2
View File
@@ -15,8 +15,8 @@ pub struct Collection {
/// The generic collection data /// The generic collection data
#[derive(Debug, serde::Serialize, serde::Deserialize)] #[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct GenericCollection { pub struct GenericCollection {
/// The collection's name /// The collection's title
pub name: String, pub title: String,
/// The collection's overview /// The collection's overview
pub overview: String, pub overview: String,
} }
+56 -4
View File
@@ -1,3 +1,6 @@
#[cfg(feature = "tmdb")]
use flix_tmdb::model::ShowId;
use chrono::NaiveDate; use chrono::NaiveDate;
/// An Episode container /// An Episode container
@@ -5,17 +8,66 @@ use chrono::NaiveDate;
pub struct Episode { pub struct Episode {
/// The generic episode data /// The generic episode data
pub episode: GenericEpisode, pub episode: GenericEpisode,
/// The TMDB episode data
#[cfg(feature = "tmdb")]
pub tmdb: Option<TmdbEpisode>,
}
/// A wrapper for handling single and multi-episode entries
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(untagged)]
pub enum EpisodeNumber {
/// The entry contains a single episode
Single {
/// The episode's number
number: u32,
},
/// The entry contains multiple episodes
Multiple {
/// The list of episode numbers
numbers: Vec<u32>,
},
}
impl EpisodeNumber {
/// Get the primary episode number of this episode
pub fn primary_episode_number(&self) -> Option<u32> {
match self {
EpisodeNumber::Single { number } => Some(*number),
EpisodeNumber::Multiple { numbers } => numbers.first().copied(),
}
}
/// Get additional episode numbers of this episode
pub fn additional_episode_numbers(&self) -> Vec<u32> {
match self {
EpisodeNumber::Single { number: _ } => vec![],
EpisodeNumber::Multiple { numbers } => numbers.iter().skip(1).copied().collect(),
}
}
} }
/// The generic episode data /// The generic episode data
#[derive(Debug, serde::Serialize, serde::Deserialize)] #[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct GenericEpisode { pub struct GenericEpisode {
/// The episode's number /// The episode's number(s)
pub number: i32, #[serde(flatten)]
/// The episode's name pub number: EpisodeNumber,
pub name: String, /// The episode's season's number
pub season: u32,
/// The episode's title
pub title: String,
/// The episode's overview /// The episode's overview
pub overview: String, pub overview: String,
/// The episode's air date /// The episode's air date
pub air_date: NaiveDate, pub air_date: NaiveDate,
} }
/// The TMDB show data
#[cfg(feature = "tmdb")]
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct TmdbEpisode {
/// The episodes's show's TMDB ID
pub show_id: ShowId,
}
+3 -3
View File
@@ -1,5 +1,5 @@
#[cfg(feature = "tmdb")] #[cfg(feature = "tmdb")]
use flix_tmdb::model::{CollectionId, MovieGenreId, MovieId}; use flix_tmdb::model::{MovieGenreId, MovieId};
use chrono::NaiveDate; use chrono::NaiveDate;
@@ -21,6 +21,8 @@ pub struct GenericMovie {
pub title: String, pub title: String,
/// The movie's overview /// The movie's overview
pub overview: String, pub overview: String,
/// The movie's genres
pub genres: Vec<String>,
/// The movie's release date /// The movie's release date
pub release_date: NaiveDate, pub release_date: NaiveDate,
} }
@@ -31,8 +33,6 @@ pub struct GenericMovie {
pub struct TmdbMovie { pub struct TmdbMovie {
/// The movie's TMDB ID /// The movie's TMDB ID
pub id: MovieId, pub id: MovieId,
/// The movie's collection's TMDB ID
pub collection: Option<CollectionId>,
/// The list of genre TMDB IDs that the movie is associated with /// The list of genre TMDB IDs that the movie is associated with
pub genres: Vec<MovieGenreId>, pub genres: Vec<MovieGenreId>,
} }
+18 -3
View File
@@ -1,3 +1,6 @@
#[cfg(feature = "tmdb")]
use flix_tmdb::model::ShowId;
use chrono::NaiveDate; use chrono::NaiveDate;
/// A Season container /// A Season container
@@ -5,17 +8,29 @@ use chrono::NaiveDate;
pub struct Season { pub struct Season {
/// The generic season data /// The generic season data
pub season: GenericSeason, pub season: GenericSeason,
/// The TMDB season data
#[cfg(feature = "tmdb")]
pub tmdb: Option<TmdbSeason>,
} }
/// The generic season data /// The generic season data
#[derive(Debug, serde::Serialize, serde::Deserialize)] #[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct GenericSeason { pub struct GenericSeason {
/// The season's number /// The season's number
pub number: i32, pub number: u32,
/// The season's name /// The season's title
pub name: String, pub title: String,
/// The season's overview /// The season's overview
pub overview: String, pub overview: String,
/// The season's air date /// The season's air date
pub air_date: NaiveDate, pub air_date: NaiveDate,
} }
/// The TMDB show data
#[cfg(feature = "tmdb")]
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct TmdbSeason {
/// The season's show's TMDB ID
pub show_id: ShowId,
}
+4 -2
View File
@@ -17,10 +17,12 @@ pub struct Show {
/// The generic show data /// The generic show data
#[derive(Debug, serde::Serialize, serde::Deserialize)] #[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct GenericShow { pub struct GenericShow {
/// The show's name /// The show's title
pub name: String, pub title: String,
/// The show's overview /// The show's overview
pub overview: String, pub overview: String,
/// The show's genres
pub genres: Vec<String>,
/// The show's air date /// The show's air date
pub air_date: NaiveDate, pub air_date: NaiveDate,
} }
+2 -2
View File
@@ -15,8 +15,8 @@ pub struct Verse {
/// The generic verse data /// The generic verse data
#[derive(Debug, serde::Serialize, serde::Deserialize)] #[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct GenericVerse { pub struct GenericVerse {
/// The verse's name /// The verse's title
pub name: String, pub title: String,
/// The verse's overview /// The verse's overview
pub overview: String, pub overview: String,
} }
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "flix-tmdb" name = "flix-tmdb"
version = "0.0.1" version = "0.0.6"
categories = [] categories = []
description = "Clients and models for fetching data from TMDB" description = "Clients and models for fetching data from TMDB"
+2 -2
View File
@@ -1,5 +1,5 @@
# flix # flix-tmdb
[![Crates Version](https://img.shields.io/crates/v/flix.svg)](https://crates.io/crates/flix) [![Crates Version](https://img.shields.io/crates/v/flix-tmdb.svg)](https://crates.io/crates/flix-tmdb)
A library providing clients and models for fetching data from TMDB A library providing clients and models for fetching data from TMDB
+2 -2
View File
@@ -22,8 +22,8 @@ impl Client {
pub async fn get_details( pub async fn get_details(
&self, &self,
id: impl Into<ShowId>, id: impl Into<ShowId>,
season: impl Into<i32>, season: impl Into<u32>,
episode: impl Into<i32>, episode: impl Into<u32>,
language: Option<&str>, language: Option<&str>,
) -> Result<Episode, Error> { ) -> Result<Episode, Error> {
Ok(self Ok(self
+1 -1
View File
@@ -22,7 +22,7 @@ impl Client {
pub async fn get_details( pub async fn get_details(
&self, &self,
id: impl Into<ShowId>, id: impl Into<ShowId>,
season: impl Into<i32>, season: impl Into<u32>,
language: Option<&str>, language: Option<&str>,
) -> Result<Season, Error> { ) -> Result<Season, Error> {
Ok(self Ok(self
+5 -4
View File
@@ -1,12 +1,13 @@
use super::{CollectionId, MovieId}; use super::{CollectionId, MovieId};
/// A deserialized Collection from the TMDB API /// A deserialized Collection from the TMDB API
#[derive(Debug, serde::Deserialize)] #[derive(Debug, Clone, serde::Deserialize)]
pub struct Collection { pub struct Collection {
/// The collection's TMDB ID /// The collection's TMDB ID
pub id: CollectionId, pub id: CollectionId,
/// The collection's name /// The collection's title
pub name: String, #[serde(rename = "name")]
pub title: String,
/// The collection's overview /// The collection's overview
pub overview: String, pub overview: String,
/// The list of movies that are part of this collection /// The list of movies that are part of this collection
@@ -15,7 +16,7 @@ pub struct Collection {
} }
/// A deserialized collection item from the TMDB API /// A deserialized collection item from the TMDB API
#[derive(Debug, serde::Deserialize)] #[derive(Debug, Clone, serde::Deserialize)]
pub struct Item { pub struct Item {
/// The movie's TMDB ID /// The movie's TMDB ID
pub id: MovieId, pub id: MovieId,
+5 -4
View File
@@ -1,12 +1,13 @@
use chrono::NaiveDate; use chrono::NaiveDate;
/// A deserialized Episode from the TMDB API /// A deserialized Episode from the TMDB API
#[derive(Debug, serde::Deserialize)] #[derive(Debug, Clone, serde::Deserialize)]
pub struct Episode { pub struct Episode {
/// The episode's number /// The episode's number
pub episode_number: i32, pub episode_number: u32,
/// The episode's name /// The episode's title
pub name: String, #[serde(rename = "name")]
pub title: String,
/// The episode's overview /// The episode's overview
pub overview: String, pub overview: String,
/// The episode's air date /// The episode's air date
+2 -2
View File
@@ -1,7 +1,7 @@
use super::id::{MovieGenreId, ShowGenreId}; use super::id::{MovieGenreId, ShowGenreId};
/// A deserialized movie Genre from the TMDB API /// A deserialized movie Genre from the TMDB API
#[derive(Debug, serde::Deserialize)] #[derive(Debug, Clone, serde::Deserialize)]
pub struct MovieGenre { pub struct MovieGenre {
/// The genre's TMDB ID /// The genre's TMDB ID
pub id: MovieGenreId, pub id: MovieGenreId,
@@ -10,7 +10,7 @@ pub struct MovieGenre {
} }
/// A deserialized show Genre from the TMDB API /// A deserialized show Genre from the TMDB API
#[derive(Debug, serde::Deserialize)] #[derive(Debug, Clone, serde::Deserialize)]
pub struct ShowGenre { pub struct ShowGenre {
/// The genre's TMDB ID /// The genre's TMDB ID
pub id: ShowGenreId, pub id: ShowGenreId,
+13 -2
View File
@@ -1,4 +1,5 @@
use core::fmt; use core::fmt;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData; use core::marker::PhantomData;
/// The TMDB ID type of a movie genre /// The TMDB ID type of a movie genre
@@ -18,8 +19,11 @@ pub enum Collection {}
pub enum Movie {} pub enum Movie {}
pub enum Show {} pub enum Show {}
type Inner = i32; /// The inner type of TmdbId
pub type Inner = u32;
/// Wraps an ID from TMDB, the generic parameter is to enforce that
/// IDs for different types of media are not interchangeable
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
#[serde(transparent)] #[serde(transparent)]
#[repr(transparent)] #[repr(transparent)]
@@ -30,7 +34,8 @@ pub struct TmdbId<T> {
} }
impl<T> TmdbId<T> { impl<T> TmdbId<T> {
pub fn inner(&self) -> Inner { /// Extract the inner value
pub fn inner(self) -> Inner {
self.inner self.inner
} }
} }
@@ -77,3 +82,9 @@ impl<T> PartialEq for TmdbId<T> {
} }
impl<T> Eq for TmdbId<T> {} impl<T> Eq for TmdbId<T> {}
impl<T> Hash for TmdbId<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner.hash(state);
}
}
+1
View File
@@ -15,3 +15,4 @@ pub use serde::*;
pub use show::*; pub use show::*;
pub use id::{CollectionId, MovieGenreId, MovieId, ShowGenreId, ShowId}; pub use id::{CollectionId, MovieGenreId, MovieId, ShowGenreId, ShowId};
pub use id::{Inner as TmdbIdInner, TmdbId};
+3 -3
View File
@@ -3,7 +3,7 @@ use chrono::NaiveDate;
use super::{CollectionId, MovieGenre, MovieId}; use super::{CollectionId, MovieGenre, MovieId};
/// A deserialized Movie from the TMDB API /// A deserialized Movie from the TMDB API
#[derive(Debug, serde::Deserialize)] #[derive(Debug, Clone, serde::Deserialize)]
pub struct Movie { pub struct Movie {
/// The movie's TMDB ID /// The movie's TMDB ID
pub id: MovieId, pub id: MovieId,
@@ -23,14 +23,14 @@ pub struct Movie {
} }
/// A deserialized movie's collection from the TMDB API /// A deserialized movie's collection from the TMDB API
#[derive(Debug, serde::Deserialize)] #[derive(Debug, Clone, serde::Deserialize)]
pub struct InCollection { pub struct InCollection {
/// The collection's TMDB ID /// The collection's TMDB ID
pub id: CollectionId, pub id: CollectionId,
} }
/// A deserialized movie status from the TMDB API /// A deserialized movie status from the TMDB API
#[derive(Debug, serde::Deserialize)] #[derive(Debug, Clone, Copy, serde::Deserialize)]
pub enum MovieStatus { pub enum MovieStatus {
/// The movie was cancelled /// The movie was cancelled
#[serde(rename = "Canceled")] #[serde(rename = "Canceled")]
+5 -4
View File
@@ -3,12 +3,13 @@ use chrono::NaiveDate;
use super::Episode; use super::Episode;
/// A deserialized Season from the TMDB API /// A deserialized Season from the TMDB API
#[derive(Debug, serde::Deserialize)] #[derive(Debug, Clone, serde::Deserialize)]
pub struct Season { pub struct Season {
/// The season's number /// The season's number
pub season_number: i32, pub season_number: u32,
/// The season's name /// The season's title
pub name: String, #[serde(rename = "name")]
pub title: String,
/// The season's overview /// The season's overview
pub overview: String, pub overview: String,
/// The season's air date /// The season's air date
+6 -5
View File
@@ -3,12 +3,13 @@ use chrono::NaiveDate;
use super::{ShowGenre, ShowId}; use super::{ShowGenre, ShowId};
/// A deserialized Show from the TMDB API /// A deserialized Show from the TMDB API
#[derive(Debug, serde::Deserialize)] #[derive(Debug, Clone, serde::Deserialize)]
pub struct Show { pub struct Show {
/// The show's TMDB ID /// The show's TMDB ID
pub id: ShowId, pub id: ShowId,
/// The show's name /// The show's title
pub name: String, #[serde(rename = "name")]
pub title: String,
/// The show's overview /// The show's overview
pub overview: String, pub overview: String,
/// The list of genres this show belongs to /// The list of genres this show belongs to
@@ -18,13 +19,13 @@ pub struct Show {
/// The show's last air date /// The show's last air date
pub last_air_date: NaiveDate, pub last_air_date: NaiveDate,
/// The number of seasons in this show /// The number of seasons in this show
pub number_of_seasons: i32, pub number_of_seasons: u32,
/// The show's status /// The show's status
pub status: ShowStatus, pub status: ShowStatus,
} }
/// A deserialized show Status from the TMDB API /// A deserialized show Status from the TMDB API
#[derive(Debug, serde::Deserialize)] #[derive(Debug, Clone, Copy, serde::Deserialize)]
pub enum ShowStatus { pub enum ShowStatus {
/// The show is returning /// The show is returning
#[serde(rename = "Returning Series")] #[serde(rename = "Returning Series")]