diff --git a/CHANGELOG.md b/CHANGELOG.md index 293299a..ef41f55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## v5.1.0 (2024-10-02) + +* Enable Renfe Cercanías GTFS dataset [#200](https://github.com/gerardcl/renfe-cli/issues/200) + ## v5.0.0 (2024-09-29) * Major refactor using GTFS data from Renfe online datasets. No more scrapping required diff --git a/Cargo.lock b/Cargo.lock index 2bf6596..b1fc40d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -132,9 +132,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.22" +version = "1.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" dependencies = [ "jobserver", "libc", @@ -462,9 +462,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "hyper" @@ -689,9 +689,12 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" +dependencies = [ + "portable-atomic", +] [[package]] name = "password-hash" @@ -922,7 +925,7 @@ dependencies = [ [[package]] name = "renfe-cli" -version = "5.0.0" +version = "5.1.0" dependencies = [ "chrono", "getopts", @@ -933,9 +936,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.7" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ "base64", "bytes", @@ -1026,11 +1029,10 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64", "rustls-pki-types", ] diff --git a/Cargo.toml b/Cargo.toml index 9bda8fd..1962417 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "renfe-cli" -version = "5.0.0" +version = "5.1.0" edition = "2021" license = "BSD-3-Clause" description = "CLI for searching Renfe train timetables in the Spanish country" readme = "README.md" homepage = "https://github.com/gerardcl/renfe-cli" repository = "https://github.com/gerardcl/renfe-cli" -keywords = ["cli", "timetables", "trains", "renfe", "spain"] +keywords = ["cli", "timetables", "schedules", "trains", "renfe", "spain"] categories = ["command-line-utilities"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/README.md b/README.md index 1c14ac8..e20a3c1 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,15 @@ Get faster Renfe trains timetables in your terminal, with Python3.7+ support. No longer need to open the browser! Just keep using your terminal 😀 +It supports both [Horarios de alta velocidad, larga distancia y media distancia](https://data.renfe.com/dataset/horarios-de-alta-velocidad-larga-distancia-y-media-distancia) (default option, as in the web) and [Renfe Cercanías](https://data.renfe.com/dataset/horarios-cercanias) GTFS datasets. + `renfe-cli` is written in [Rust](https://www.rust-lang.org/) (since v4.0.0) and published to [pypi.org](https://pypi.org/project/renfe-cli/) as a Python package (CLI and library). See the [changelog](https://github.com/gerardcl/renfe-cli/blob/master/CHANGELOG.md). **NOTE** since I am more often using Rodalies trains I have created [rodalies-cli](https://github.com/gerardcl/rodalies-cli). I hope you like it too! - **DISCLAIMER**: Renfe's GTFS dataset might not be in sync with autonomic train schedules (e.g. Rodalies de la Generalitat de Catalunya), hence Renfe Cercanias train types (e.g.: REGIONAL or MD type) might not be accurate. For that, please use autonomic data/apps (.e.g: [rodalies-cli](https://github.com/gerardcl/rodalies-cli)). + **DISCLAIMER**: Renfe's GTFS dataset might not be in sync with autonomic train schedules systems (e.g. Rodalies de la Generalitat de Catalunya), hence Renfe Cercanias train types (e.g.: REGIONAL or MD type) might not be accurate, or when using the `cercanias` flag you won't find timetables for the stations belonging to autonomic systems. For that, please use autonomic data/apps (.e.g: [rodalies-cli](https://github.com/gerardcl/rodalies-cli)). ## Installation @@ -23,7 +25,7 @@ pip install renfe-cli --upgrade ## Usage (CLI) -The CLI uses the official and latest Renfe's GTFS dataset, from [Horarios de alta velocidad, larga distancia y media distancia](https://data.renfe.com/dataset/horarios-de-alta-velocidad-larga-distancia-y-media-distancia). +The CLI uses the official and latest Renfe's GTFS dataset, from [Horarios de alta velocidad, larga distancia y media distancia](https://data.renfe.com/dataset/horarios-de-alta-velocidad-larga-distancia-y-media-distancia), by default. Optionally, one can enable searching over [Renfe Cercanías GTFS dataset](https://data.renfe.com/dataset/horarios-cercanias) (expect longer load time in this case). ```bash $ renfe-cli -h @@ -36,16 +38,17 @@ Options: -m, --month MONTH Set the Month (default: today's month) -y, --year YEAR Set the Year (default: today's year) -s, --sort Option to sort the timetable by Duration + -c, --cercanias Option to search over Renfe Cercanías -h, --help Print this help menu ``` ### **Getting the timetable** -Let's show an example of minimal inputs (origin and destination stations) with specific date: +Let's show an example of minimal inputs (origin and destination stations) with specific date and default GTFS dataset: ```bash $ renfe-cli -f girona -t "puerta de atocha" -d 30 -Loading GTFS data from Renfe web +Loading default GTFS data from Renfe web - Alta velocidad, Larga distancia y Media distancia Provided input 'girona' does a match with 'Estación de tren Girona' Provided input 'puerta de atocha' does a match with 'Estación de tren Madrid-Puerta de Atocha' Today is: 2024-9-29 @@ -70,6 +73,38 @@ Destination station: Estación de tren Madrid-Puerta de Atocha =========================================================== ``` +Let's show an example using Renfe Cercanías GTFS dataset: + +```bash +$ renfe-cli -f chamartín -t "tres cantos" -c +Loading Cercanías GTFS data from Renfe web - long load time +Provided input 'chamartín' does a match with 'Station { name: "Estación de tren Madrid-Chamartín-Clara Campoamor", id: "17000" }' +Provided input 'tres cantos' does a match with 'Station { name: "Estación de tren Tres Cantos (apt)", id: "17004" }' +Today is: 2024-10-2 +Searching timetable for date: 2024-10-2 +Origin station: Estación de tren Madrid-Chamartín-Clara Campoamor +Destination station: Estación de tren Tres Cantos (apt) + +=========================TIMETABLE========================= + Train | Departure | Arrival | Duration +----------------------------------------------------------- + C4b | 05:06 | 05:22 | 00:16 +----------------------------------------------------------- + C4b | 05:38 | 05:55 | 00:17 +----------------------------------------------------------- + C4b | 06:10 | 06:27 | 00:17 +----------------------------------------------------------- +......... +......... +----------------------------------------------------------- + C4b | 21:56 | 22:13 | 00:17 +----------------------------------------------------------- + C4b | 22:20 | 22:37 | 00:17 +----------------------------------------------------------- + C4b | 23:16 | 23:33 | 00:17 +=========================================================== +``` + ## Usage (Library) `renfe-cli` can be imported as a python package into your project, offering utilities when willing to deal with the Renfe search web site. @@ -82,7 +117,20 @@ Type "help", "copyright", "credits" or "license" for more information. >>> renfe = renfe_cli. renfe_cli.Renfe() renfe_cli.Schedule( renfe_cli.Station( renfe_cli.main() renfe_cli.renfe_cli >>> renfe = renfe_cli.Renfe() -Loading GTFS data from Renfe web +Traceback (most recent call last): + File "", line 1, in +TypeError: Renfe.__new__() missing 1 required positional argument: 'cercanias' +>>> renfe = renfe_cli.Renfe(False) +Loading default GTFS data from Renfe web - Alta velocidad, Larga distancia y Media distancia +GTFS data: + Read in 2171 ms + Stops: 793 + Routes: 644 + Trips: 4150 + Agencies: 1 + Shapes: 0 + Fare attributes: 0 + Feed info: 0 >>> renfe.filter_station("madrid") Traceback (most recent call last): File "", line 1, in @@ -138,10 +186,10 @@ $ maturin develop 🔗 Found pyo3 bindings with abi3 support for Python ≥ 3.7 🐍 Not using a specific python interpreter 📡 Using build options features from pyproject.toml - Compiling renfe-cli v4.1.0 (/path/to/renfe-cli) + Compiling renfe-cli v5.1.0 (/path/to/renfe-cli) Finished dev [unoptimized + debuginfo] target(s) in 7.07s -📦 Built wheel for abi3 Python ≥ 3.7 to /tmp/.tmpDsjowL/renfe_cli-4.1.0-cp37-abi3-linux_x86_64.whl -🛠 Installed renfe-cli-4.1.0 +📦 Built wheel for abi3 Python ≥ 3.7 to /tmp/.tmpDsjowL/renfe_cli-5.1.0-cp37-abi3-linux_x86_64.whl +🛠 Installed renfe-cli-5.1.0 ``` Maturin takes care of compiling the rust code, generating the bindings for python and installing the package for local use (as library or binary/CLI). diff --git a/pyproject.toml b/pyproject.toml index 46d9993..7c33e87 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,6 @@ classifiers = [ "Operating System :: Microsoft :: Windows", "Topic :: Utilities", "Topic :: Terminals", - "Topic :: Text Processing :: Markup :: HTML", ] dynamic = ["version"] diff --git a/src/cli.rs b/src/cli.rs index f93fc1c..63c5c36 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -24,7 +24,7 @@ pub fn main() -> PyResult<()> { return Ok(()); } - let mut renfe = Renfe::new()?; + let mut renfe = Renfe::new(matches.opt_present("c"))?; let origin = renfe.filter_station(matches.opt_str("f").expect("Missing origin station"))?; let destination = @@ -74,6 +74,7 @@ fn set_opts() -> Options { ); opts.optopt("y", "year", "Set the Year (default: today's year)", "YEAR"); opts.optflag("s", "sort", "Option to sort the timetable by Duration"); + opts.optflag("c", "cercanias", "Option to search over Renfe Cercanías"); opts.optflag("h", "help", "Print this help menu"); opts diff --git a/src/renfe.rs b/src/renfe.rs index 4e88ddd..f153fa6 100644 --- a/src/renfe.rs +++ b/src/renfe.rs @@ -32,11 +32,18 @@ pub struct Station { #[pymethods] impl Renfe { #[new] - pub fn new() -> PyResult { - println!("Loading GTFS data from Renfe web"); - + pub fn new(cercanias: bool) -> PyResult { let mut res = reqwest::blocking::get( - "https://ssl.renfe.com/gtransit/Fichero_AV_LD/google_transit.zip", + match cercanias { + false => { + println!("Loading default GTFS data from Renfe web - Alta velocidad, Larga distancia y Media distancia"); + "https://ssl.renfe.com/gtransit/Fichero_AV_LD/google_transit.zip" + }, + true => { + println!("Loading Cercanías GTFS data from Renfe web - long load time"); + "https://ssl.renfe.com/ftransit/Fichero_CER_FOMENTO/fomento_transit.zip" + }, + }, ) .expect("Error downloading GTFS zip file"); let mut body = Vec::new(); @@ -44,7 +51,8 @@ impl Renfe { let cursor = std::io::Cursor::new(body); let gtfs = Gtfs::from_reader(cursor).expect("Error parsing GTFS zip"); - // gtfs.print_stats(); + + gtfs.print_stats(); Ok(Renfe { gtfs, @@ -143,18 +151,22 @@ impl Renfe { let time_origin = origin.departure_time.unwrap(); let time_destination = destination.arrival_time.unwrap(); let departure_time = NaiveTime::from_hms_opt( - time_origin / 3600, + (time_origin / 3600) % 24, time_origin % 3600 / 60, time_origin % 60, ) .unwrap(); let arrival_time = NaiveTime::from_hms_opt( - time_destination / 3600, + (time_destination / 3600) % 24, time_destination % 3600 / 60, time_destination % 60, ) .unwrap(); - let duration = arrival_time.signed_duration_since(departure_time); + + let mut duration = arrival_time.signed_duration_since(departure_time); + if time_destination >= 86400 { + duration = duration.checked_add(&TimeDelta::seconds(86400)).unwrap(); + } schedules.push(Schedule { train_type: gtfs