search stops
Some checks failed
Create and publish a Docker image / build-and-push-image (push) Has been cancelled
Some checks failed
Create and publish a Docker image / build-and-push-image (push) Has been cancelled
This commit is contained in:
parent
e41e8adefc
commit
458f71530f
8 changed files with 119 additions and 11 deletions
42
README.md
42
README.md
|
|
@ -13,7 +13,47 @@ live information for gtfs data feeds (though is specifically tailored to SEPTA).
|
|||
- [] implement support for connecting legs of a Regional Rail trip
|
||||
- [] work on providing a better experience with non-SEPTA gtfs files
|
||||
- [] simple account system to save info such as work commute/fav routes
|
||||
- [] parse gtfs data ourselves instead of using library
|
||||
- [] support more of the gtfs specification
|
||||
|
||||
## Building
|
||||
|
||||
The build system for this isn't extremely straightforward. I have a shell.nix that
|
||||
contains some shell utils specific to this project, but don't have a flake setup
|
||||
that would allow you to easily build. If you have a newer rust toolchain installed,
|
||||
you should be able to run this with Cargo.
|
||||
|
||||
I also provide a Dockerfile you can use as the base for a dev container.
|
||||
|
||||
## Running
|
||||
|
||||
There's a config file in this repository that has a format for specifying GTFS
|
||||
file locations as well as 'annotations' to those files to enrich them. Currently,
|
||||
the following annotations exist:
|
||||
|
||||
- **multiplatform_stops:** used to combine multiple stops into one stop as though
|
||||
each 'sub-stop' is it's own platform. This is useful for when a transit authority
|
||||
(specifically one in southeastern PA) does not provide [stop_areas.txt](https://gtfs.org/documentation/schedule/reference/#stop_areastxt).
|
||||
|
||||
```yaml
|
||||
- id: 'WTC'
|
||||
name: 'Wissahickon Transit Center'
|
||||
platform_station_ids:
|
||||
- 'SEPTABUS_2'
|
||||
- 'SEPTABUS_31032'
|
||||
- 'SEPTABUS_32980'
|
||||
- 'SEPTABUS_32988'
|
||||
- 'SEPTABUS_32989'
|
||||
- 'SEPTABUS_32990'
|
||||
- 'SEPTABUS_32992'
|
||||
- 'SEPTABUS_32993'
|
||||
- 'SEPTARAIL_90220'
|
||||
```
|
||||
|
||||
This project uses postgres (via sqlx) to store an archive of realtime data, though
|
||||
it is not required to run SEPTASTIC (all transit data is stored in-memory).
|
||||
|
||||
---
|
||||
|
||||
I have an instance of this running at [septastic.net](https://septastic.net)
|
||||
I have an instance of this running at [septastic.net](https://septastic.net),
|
||||
feel free to check it out.
|
||||
|
|
|
|||
|
|
@ -4,13 +4,12 @@ use crate::{
|
|||
templates::TripPerspective,
|
||||
};
|
||||
use actix_web::{
|
||||
HttpResponse, Responder, get,
|
||||
web::{self, Data},
|
||||
HttpResponse, Responder, get, post, web::{self, Data}
|
||||
};
|
||||
use askama::Template;
|
||||
use chrono::{TimeDelta, Timelike};
|
||||
use chrono_tz::America::New_York;
|
||||
use libseptastic::stop_schedule::{SeatAvailability, Trip, TripTracking};
|
||||
use libseptastic::{stop::Stop, stop_schedule::{SeatAvailability, Trip, TripTracking}};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_qs::actix::QsQuery;
|
||||
use std::{
|
||||
|
|
@ -193,6 +192,39 @@ async fn get_stops_html(state: Data<Arc<AppState>>, resp: SessionResponse) -> im
|
|||
)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct StringSearch {
|
||||
search: String
|
||||
}
|
||||
|
||||
#[post("/stops/search")]
|
||||
async fn search_stops_html(state: Data<Arc<AppState>>, params: web::Form<StringSearch>) -> impl Responder {
|
||||
let results_limit = 25;
|
||||
let search_str = params.search.to_lowercase();
|
||||
let stops: Vec<Stop> = state
|
||||
.gtfs_service
|
||||
.get_all_stops()
|
||||
.iter()
|
||||
.filter_map(|f| {
|
||||
// Non-ideal
|
||||
if f.1.name.to_lowercase().contains(&search_str) ||
|
||||
f.1.id.to_lowercase().contains(&search_str) {
|
||||
Some(libseptastic::stop::Stop::clone(f.1))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
HttpResponse::Ok().body(crate::templates::StopSearchResults {
|
||||
results: if stops.len() > results_limit {
|
||||
stops[..results_limit].to_vec()
|
||||
} else {
|
||||
stops
|
||||
}
|
||||
}.render().unwrap())
|
||||
}
|
||||
|
||||
#[get("/stop/{stop_id}/table")]
|
||||
async fn get_stop_table_html(
|
||||
state: Data<Arc<AppState>>,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ pub struct AppState {
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() -> ::anyhow::Result<()> {
|
||||
env_logger::init_from_env(Env::default().default_filter_or("septastic_api=info"));
|
||||
env_logger::init_from_env(Env::default().default_filter_or("septastic_web=info"));
|
||||
dotenv().ok();
|
||||
|
||||
let version: &str = option_env!("CARGO_PKG_VERSION").expect("Expected package version");
|
||||
|
|
@ -54,6 +54,7 @@ async fn main() -> ::anyhow::Result<()> {
|
|||
.service(controllers::route::get_routes_json)
|
||||
.service(controllers::stop::get_stops_html)
|
||||
.service(controllers::stop::get_stop_html)
|
||||
.service(controllers::stop::search_stops_html)
|
||||
.service(controllers::stop::get_stop_table_html)
|
||||
.service(controllers::index::get_index_html)
|
||||
.service(actix_files::Files::new("/assets", "./assets"))
|
||||
|
|
|
|||
|
|
@ -325,7 +325,6 @@ impl GtfsPullService {
|
|||
) -> anyhow::Result<()> {
|
||||
for route in >fs.routes {
|
||||
let global_rt_id = make_global_id!(prefix, route.1.id);
|
||||
info!("{}", global_rt_id);
|
||||
|
||||
let rt_name = match route.1.long_name.clone() {
|
||||
Some(x) => x,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use chrono::Timelike;
|
||||
use chrono_tz::America::New_York;
|
||||
use libseptastic::stop::Stop;
|
||||
use libseptastic::stop_schedule::TripTracking::Tracked;
|
||||
use libseptastic::{
|
||||
direction::Direction,
|
||||
|
|
@ -92,6 +93,12 @@ pub struct StopTableTemplate {
|
|||
pub stop_id: String,
|
||||
}
|
||||
|
||||
#[derive(askama::Template)]
|
||||
#[template(path = "stop_search_results.html")]
|
||||
pub struct StopSearchResults {
|
||||
pub results: Vec<Stop>
|
||||
}
|
||||
|
||||
pub fn build_timetables(directions: Vec<Direction>, trips: Vec<Trip>) -> Vec<TimetableDirection> {
|
||||
let mut results = Vec::new();
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,15 @@
|
|||
<i>A fantastic way to ride SEPTA</i>
|
||||
</p>
|
||||
<p style="margin-top: 25px;">
|
||||
SEPTASTIC is a website and (a soon to be) mobile app. Its purpose is to provide
|
||||
information about how to ride SEPTA (and connecting transit authorities) in a
|
||||
quick and information-rich manner.
|
||||
SEPTASTIC is a website which provides information about riding SEPTA. It's
|
||||
source code is available at
|
||||
<a href="https://git.nickorlow.com/nickorlow/septastic">git.nickorlow.com</a>
|
||||
</p>
|
||||
|
||||
<p style="margin-top: 25px; margin-bottom: 25px;">
|
||||
Currently, all this website has is <a href="/routes">timetables for every
|
||||
SEPTA route</a>. More to come soon!
|
||||
This website is mostly for personal use, and thus the interface and data
|
||||
is tailored to my SEPTA riding experience. This manifests in a couple of
|
||||
weird things, such as the non-existent 'Susquehanna Transit Center'.
|
||||
</p>
|
||||
|
||||
|
||||
|
|
|
|||
12
web/templates/stop_search_results.html
Normal file
12
web/templates/stop_search_results.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{% for stop in results %}
|
||||
<a href="/stop/{{ stop.id }}"
|
||||
style="display: flex;
|
||||
justify-content: space-between">
|
||||
<p class="line-link">[ {{ stop.name }}</p>
|
||||
<p>]</p>
|
||||
</a>
|
||||
{% endfor %}
|
||||
|
||||
{% if results.len() == 0 %}
|
||||
<p>No results found</p>
|
||||
{% endif %}
|
||||
|
|
@ -14,6 +14,19 @@
|
|||
</a>
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>
|
||||
<h2>Other Stops</h2>
|
||||
</legend>
|
||||
<p style="margin-top: 10px; margin-bottom: 10px;">SEPTA has 13,000+ stops, search for yours here</p>
|
||||
<input style="width: 100%;" type="search"
|
||||
name="search" placeholder="Begin Typing To Search Stops..."
|
||||
hx-post="/stops/search"
|
||||
hx-trigger="input changed delay:500ms, keyup[key=='Enter'], load"
|
||||
hx-target="#stop-list">
|
||||
<div id="stop-list">
|
||||
</div>
|
||||
</fieldset>
|
||||
<style>
|
||||
.line-link, .lines-label {
|
||||
white-space: pre;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue