Author: Adam Pioterek <adam.pioterek@protonmail.ch>
initial commit
.idea/misc.xml | 12 app/build.gradle | 20 + app/src/main/AndroidManifest.xml | 11 app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt | 93 ++++++ app/src/main/res/drawable/logo.xml | 55 +++ app/src/main/res/layout/activity_main.xml | 20 + app/src/main/res/values-night/colors.xml | 2 app/src/main/res/values-night/styles.xml | 9 app/src/main/res/values-pl/strings.xml | 2 | 0 | 3 build.gradle | 4 gradle/wrapper/gradle-wrapper.properties | 4 research/badges.md | 5 research/datasources.md | 9 research/scraper.py | 193 +++++++++++++
diff --git a/.idea/misc.xml b/.idea/misc.xml index 7c1371c54da8eafc01d4252c2465d08c996e6451..ba7052b8197ddf8ba8756022d905d03055c7ad60 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -24,17 +24,7 @@ </value> </option> </component> - <component name="ProjectLevelVcsManager" settingsEditedManually="false"> - <OptionsSetting value="true" id="Add" /> - <OptionsSetting value="true" id="Remove" /> - <OptionsSetting value="true" id="Checkout" /> - <OptionsSetting value="true" id="Update" /> - <OptionsSetting value="true" id="Status" /> - <OptionsSetting value="true" id="Edit" /> - <ConfirmationsSetting value="0" id="Add" /> - <ConfirmationsSetting value="0" id="Remove" /> - </component> - <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> + <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> <output url="file://$PROJECT_DIR$/build/classes" /> </component> <component name="ProjectType"> diff --git a/app/build.gradle b/app/build.gradle index 6e3219af510796cf25b8dbf28e6c506b01583277..6d5f42648d5fd1a6ba9774ddcad3d665dc161867 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,15 +1,17 @@ apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' android { compileSdkVersion 25 - buildToolsVersion "25.0.2" + buildToolsVersion "25.0.3" defaultConfig { applicationId "ml.adamsprogs.bimba" - minSdkVersion 15 + minSdkVersion 19 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + vectorDrawables.useSupportLibrary = true } buildTypes { release { @@ -24,6 +26,18 @@ compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) - compile 'com.android.support:appcompat-v7:25.2.0' + compile 'com.android.support:appcompat-v7:25.3.1' + compile 'com.android.support:cardview-v7:25.3.1' + compile 'com.android.support:design:25.3.1' + compile 'com.android.support:support-vector-drawable:25.4.0' testCompile 'junit:junit:4.12' + compile 'com.android.support.constraint:constraint-layout:1.0.2' + compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" + compile 'com.github.arimorty:floatingsearchview:2.1.1' +} +repositories { + maven { + url "https://maven.google.com" + } + mavenCentral() } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 528acc4bbb7cbdfe62c838439b890116ecc9ffe1..4e04cbad3e2b067a1dcc24ea26c2b9a77a7dacd8 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,13 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="ml.adamsprogs.bimba"> <application android:allowBackup="true" - android:icon="@mipmap/ic_launcher" + android:icon="@drawable/logo" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> + <activity android:name=".MainActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> </application> -</manifest> +</manifest> \ No newline at end of file diff --git a/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt b/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..40075d65bc0b76db5a03373c5c3f2541da95c6fa --- /dev/null +++ b/app/src/main/java/ml/adamsprogs/bimba/MainActivity.kt @@ -0,0 +1,93 @@ +package ml.adamsprogs.bimba + +import android.content.Context +import android.os.Build +import android.os.Bundle +import android.os.Parcel +import android.os.Parcelable +import android.support.v7.app.AppCompatActivity +import android.text.Html +import android.widget.Toast +import com.arlib.floatingsearchview.FloatingSearchView +import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion + + +class MainActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + val context = this as Context + + val stops = listOf(Suggestion("Kołłątaja\n610 -> Dębiec"), Suggestion("Dębiecka\n610 -> Górczyn")) //todo get from db + val searchView = findViewById(R.id.search_view) as FloatingSearchView + + searchView.setOnQueryChangeListener({ _, newQuery -> + searchView.swapSuggestions(stops.filter { deAccent(it.body.split("\n")[0]).contains(newQuery, true) }) + }) + + searchView.setOnSearchListener(object : FloatingSearchView.OnSearchListener { + override fun onSuggestionClicked(searchSuggestion: SearchSuggestion) { + Toast.makeText(context, "clicked "+ searchSuggestion.body, Toast.LENGTH_SHORT).show() + //todo to next screen + } + override fun onSearchAction(query: String) { + } + }) + + searchView.setOnBindSuggestionCallback { _, _, textView, item, _ -> + val suggestion = item as Suggestion + val text = suggestion.body.split("\n") + val t = "<small><font color=\"#a0a0a0\">" + text[1] + "</font></small>" + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + textView.text = Html.fromHtml(text[0]+"<br/>"+t, Html.FROM_HTML_MODE_LEGACY) + } else { + @Suppress("DEPRECATION") + textView.text = Html.fromHtml(text[0]+"<br/>"+t) + } + } + + //todo searchView.attachNavigationDrawerToMenuButton(mDrawerLayout) + } + + fun deAccent(str: String): String { + var result = str.replace('ę', 'e') + result = result.replace('ó', 'o') + result = result.replace('ą', 'a') + result = result.replace('ś', 's') + result = result.replace('ł', 'l') + result = result.replace('ż', 'ż') + result = result.replace('ź', 'ź') + result = result.replace('ć', 'ć') + result = result.replace('ń', 'n') + return result + } + + class Suggestion(text: String) : SearchSuggestion { + private val body: String = text + + constructor(parcel: Parcel) : this(parcel.readString()) + + override fun describeContents(): Int { + TODO("not implemented") + } + + override fun writeToParcel(dest: Parcel?, flags: Int) { + TODO("not implemented") + } + + override fun getBody(): String { + return body + } + + companion object CREATOR : Parcelable.Creator<Suggestion> { + override fun createFromParcel(parcel: Parcel): Suggestion { + return Suggestion(parcel) + } + + override fun newArray(size: Int): Array<Suggestion?> { + return arrayOfNulls(size) + } + } + } +} diff --git a/app/src/main/res/drawable/logo.xml b/app/src/main/res/drawable/logo.xml new file mode 100644 index 0000000000000000000000000000000000000000..235d29e4958f2c5944427f6f3b288c1f2d4e280b --- /dev/null +++ b/app/src/main/res/drawable/logo.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="512dp" + android:height="512dp" + android:viewportWidth="512" + android:viewportHeight="512"> + + <group + android:translateY="215"> + <path + android:fillColor="#00ff00" + android:strokeColor="#ffffff" + android:strokeAlpha="0.15463915" + android:strokeWidth="0.30951566" + android:pathData="M 0.15475783 -214.84525 H 511.84524783 V 296.84524 H 0.15475783 V -214.84525 Z" /> + <path + android:fillColor="#ffff00" + android:strokeColor="#ffffff" + android:strokeAlpha="0.15463915" + android:strokeWidth="0.26458332" + android:pathData="M 264.58334 -195.880935 C 286.293391181 -195.880935 303.892865 -178.281461181 303.892865 -156.57141 C 303.892865 -134.861358819 286.293391181 -117.261885 264.58334 -117.261885 C 242.873288819 -117.261885 225.273815 -134.861358819 225.273815 -156.57141 C 225.273815 -178.281461181 242.873288819 -195.880935 264.58334 -195.880935 Z" /> + <path + android:fillColor="#ffff00" + android:strokeColor="#ffffff" + android:strokeAlpha="0.15463915" + android:strokeWidth="0.26458332" + android:pathData="M 258.53571 216.869064 C 276.905753434 216.869064 291.797616 231.760926566 291.797616 250.13097 C 291.797616 268.501013434 276.905753434 283.392876 258.53571 283.392876 C 240.165666566 283.392876 225.273804 268.501013434 225.273804 250.13097 C 225.273804 231.760926566 240.165666566 216.869064 258.53571 216.869064 Z" /> + <path + android:fillColor="#ffff00" + android:strokeColor="#ffffff" + android:strokeAlpha="0.15463915" + android:strokeWidth="0.26458332" + android:pathData="M 2.4384184 66.288048 H 19.0693714 V 350.526148 H 2.4384184 V 66.288048 Z" /> + <path + android:fillColor="#ffff00" + android:strokeColor="#ffffff" + android:strokeAlpha="0.15463915" + android:strokeWidth="0.26458332" + android:pathData="M 66.288048 -286.67651 H 82.919001 V -2.43841 H 66.288048 V -286.67651 Z" /> + <group> + <path + android:fillColor="#ffff00" + android:strokeColor="#ffffff" + android:strokeAlpha="0.15463915" + android:strokeWidth="0.26458332" + android:pathData="M 143.47235 236.35587 H 160.103303 V 520.59397 H 143.47235 V 236.35587 Z" /> + <path + android:fillColor="#ffff00" + android:strokeColor="#ffffff" + android:strokeAlpha="0.15463915" + android:strokeWidth="0.26458332" + android:pathData="M 236.35587 -427.71045 H 252.986823 V -143.47235 H 236.35587 V -427.71045 Z" /> + </group> + </group> +</vector> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000000000000000000000000000000000000..2118179d144cfce2aee6e45af628f83bf862a2c5 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context="ml.adamsprogs.bimba.MainActivity"> + <com.arlib.floatingsearchview.FloatingSearchView + android:id="@+id/search_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:floatingSearch_searchBarMarginLeft="16dp" + app:floatingSearch_searchBarMarginTop="16dp" + app:floatingSearch_searchBarMarginRight="16dp" + app:floatingSearch_searchHint="Search..." + app:floatingSearch_suggestionsListAnimDuration="250" + app:floatingSearch_showSearchKey="false" + app:floatingSearch_leftActionMode="showHamburger" + app:floatingSearch_close_search_on_keyboard_dismiss="true"/> +</android.support.constraint.ConstraintLayout> diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index cde69bcccec65160d92116f20ffce4fce0b5245c..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index c133a0cbd379f5af6dbf1a899a0293ca5eccfad0..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index bfa42f0e7b91d006d22352c9ff2f134e504e3c1d..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 324e72cdd7480cb983fa1bcc7ce686e51ef87fe7..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index aee44e138434630332d88b1680f33c4b24c70ab3..0000000000000000000000000000000000000000 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml deleted file mode 100644 index 3ab3e9cbce07f7cdc941fc8ba424c05e83ed80f0..0000000000000000000000000000000000000000 --- a/app/src/main/res/values/colors.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - <color name="colorPrimary">#3F51B5</color> - <color name="colorPrimaryDark">#303F9F</color> - <color name="colorAccent">#FF4081</color> -</resources> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml deleted file mode 100644 index 5885930df6d10edf3d6df40d6556297d11f953da..0000000000000000000000000000000000000000 --- a/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,11 +0,0 @@ -<resources> - - <!-- Base application theme. --> - <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> - <!-- Customize your theme here. --> - <item name="colorPrimary">@color/colorPrimary</item> - <item name="colorPrimaryDark">@color/colorPrimaryDark</item> - <item name="colorAccent">@color/colorAccent</item> - </style> - -</resources> diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml new file mode 100644 index 0000000000000000000000000000000000000000..a6b3daec9354f9ae75cdf8d94a67446c6227dd96 --- /dev/null +++ b/app/src/main/res/values-night/colors.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources></resources> \ No newline at end of file diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000000000000000000000000000000000000..cf79209801eec4a7fa1c0f8fe8b75478f187f057 --- /dev/null +++ b/app/src/main/res/values-night/styles.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <style name="AppTheme" parent="Theme.AppCompat.NoActionBar"> + <!-- Customize your theme here. --> + <item name="colorPrimary">@color/colorPrimary</item> + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> + <item name="colorAccent">@color/colorAccent</item> + </style> +</resources> \ No newline at end of file diff --git a/app/src/main/res/values-notnight/colors.xml b/app/src/main/res/values-notnight/colors.xml new file mode 100644 index 0000000000000000000000000000000000000000..3ab3e9cbce07f7cdc941fc8ba424c05e83ed80f0 --- /dev/null +++ b/app/src/main/res/values-notnight/colors.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <color name="colorPrimary">#3F51B5</color> + <color name="colorPrimaryDark">#303F9F</color> + <color name="colorAccent">#FF4081</color> +</resources> diff --git a/app/src/main/res/values-notnight/styles.xml b/app/src/main/res/values-notnight/styles.xml new file mode 100644 index 0000000000000000000000000000000000000000..01eb5f588d1855d7fc90b2f6ef8d8dc97c260303 --- /dev/null +++ b/app/src/main/res/values-notnight/styles.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <!-- Base application theme. --> + <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> + <!-- Customize your theme here. --> + <item name="colorPrimary">@color/colorPrimary</item> + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> + <item name="colorAccent">@color/colorAccent</item> + </style> + +</resources> diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..a6b3daec9354f9ae75cdf8d94a67446c6227dd96 --- /dev/null +++ b/app/src/main/res/values-pl/strings.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources></resources> \ No newline at end of file diff --git a/build.gradle b/build.gradle index 74b2ab0dd88f66079893ee7c77a46dbace4f0fde..4b5928a5f03c5c7697af0a79987e7e6510fe2bf1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,13 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext.kotlin_version = '1.1.2-4' repositories { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.3' + classpath 'com.android.tools.build:gradle:3.0.0-alpha5' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 04e285f34080d98841a9fac832466aec720aecec..3d353ea4d1cc03c0e3c288a3862a26c1ebc247c4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Dec 28 10:00:20 PST 2015 +#Tue Jul 04 17:47:25 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-milestone-1-all.zip diff --git a/research/badges.md b/research/badges.md new file mode 100644 index 0000000000000000000000000000000000000000..34c5ea6f822b37f8dcdd400d596d52f70eb56696 --- /dev/null +++ b/research/badges.md @@ -0,0 +1,5 @@ +# CodeCov + +* [website](https://codecov.io/) +* [example android](https://github.com/codecov/example-android) +* [with travis](https://github.com/codecov/example-android/blob/master/.travis.yml) diff --git a/research/datasources.md b/research/datasources.md index 3b4ae5261eabb965ce231f7d04a9280bc4d2ed64..20a66df2c1fbfc301ed7fde011e763d0743a55dc 100644 --- a/research/datasources.md +++ b/research/datasources.md @@ -1,12 +1,3 @@ -# offline timetable - -* config: http://ztm.poznan.pl/timetablesConfig.json -* lines: http://ztm.poznan.pl/gtfs-ztm/routes_by_name.json.php -* stops-on-line: http://ztm.poznan.pl/gtfs-ztm/route_directions.html.php?route_name=6&agency_name=ZTM_MPK&json=dane -* stop-on-line: http://ztm.poznan.pl/gtfs-ztm/timetable.html.php?route_name=6&direction=0&stop_id=93&agency_name=ZTM_MPK&json=dane - * direction in {0,1} -* stops: http://ztm.poznan.pl/gtfs-ztm/places.json.php - # Poznań API * bicycles: http://egov.psnc.pl/node/29#stacje-rowerow-miejskich diff --git a/research/scraper.py b/research/scraper.py new file mode 100755 index 0000000000000000000000000000000000000000..2f6d4b1c8e16f0a8157a62fea96e2b116ba146ba --- /dev/null +++ b/research/scraper.py @@ -0,0 +1,193 @@ +#!/bin/python +""" +js interface: http://ztm.poznan.pl/themes/ztm/dist/js/app.js +nodes: http://ztm.poznan.pl/goeuropa-api/all-nodes +stops in node: http://ztm.poznan.pl/goeuropa-api/node_stops/{node:symbol} +stops: http://ztm.poznan.pl/goeuropa-api/stops-nodes +bike stations: http://ztm.poznan.pl/goeuropa-api/bike-stations + +""" +import json +import hashlib +import re +import sqlite3 +import sys +import time +import requests +from bs4 import BeautifulSoup + +def get_nodes(): + """ + get nodes + """ + session = requests.session() + + index = session.get('http://ztm.poznan.pl/goeuropa-api/all-nodes') + return [(stop['symbol'], stop['name']) for stop in json.loads(index.text)] + + +def get_stops(node): + """ + get stops + """ + session = requests.session() + + index = session.get('http://ztm.poznan.pl/goeuropa-api/node_stops/{}'.format(node)) + stops = [] + for stop in json.loads(index.text): + stop_id = stop['stop']['id'] + number = re.findall("\\d+", stop['stop']['symbol'])[0] + lat = stop['stop']['lat'] + lon = stop['stop']['lon'] + directions = ', '.join(['{} → {}'.format(transfer['name'], transfer['headsign']) + for transfer in stop['transfers']]) + stops.append((stop_id, node, number, lat, lon, directions)) + return stops + + +def get_lines(): + """ + get lines + """ + session = requests.session() + + index = session.get('http://ztm.poznan.pl/goeuropa-api/index') + soup = BeautifulSoup(index.text, 'html.parser') + + lines = {line['data-lineid']: line.text for line in + soup.findAll(attrs={'class': re.compile(r'.*\blineNo-bt\b.*')})} + + return lines + + +def get_route(line_id): + """ + get routes + """ + session = requests.session() + + index = session.get('http://ztm.poznan.pl/goeuropa-api/line-info/{}'.format(line_id)) + soup = BeautifulSoup(index.text, 'html.parser') + directions = soup.findAll(attrs={'class': re.compile(r'.*\baccordion-item\b.*')}) + routes = {} + for direction in directions: + direction_id = direction['data-directionid'] + route = [{'id': stop.find('a')['data-stopid'], 'name': stop['data-name'], + 'onDemand': re.search('stop-onDemand', str(stop['class'])) != None} + for stop in direction.findAll(attrs={'class': re.compile(r'.*\bstop-itm\b.*')})] + routes[direction_id] = route + return routes + + +def get_stop_times(stop_id, line_id, direction_id): + """ + get timetable + """ + session = requests.session() + + index = session.post('http://ztm.poznan.pl/goeuropa-api/stop-info/{}/{}'. + format(stop_id, line_id), data={'directionId': direction_id}) + soup = BeautifulSoup(index.text, 'html.parser') + legends = {} + for row in soup.find(attrs={'class': re.compile(r'.*\blegend-box\b.*')}).findAll('li'): + row = row.text.split('-') + row[0] = row[0].rstrip() + row[1] = row[1].lstrip() + if row[0] != '_': + legends[row[0]] = '-'.join(row[1:]) + schedules = {} + for mode in soup.findAll(attrs={'class': re.compile(r'.*\bmode-tab\b.*')}): + mode_name = mode['data-mode'] + schedule = {row.find('th').text: [ + {'time': minute.text, 'lowFloor': re.search('n-line', str(minute['class'])) != None} + for minute in row.findAll('a')] + for row in mode.find(attrs={'class': re.compile(r'.*\bscheduler-hours\b.*')}). + findAll('tr')} + schedule_2 = {hour: times for hour, times in schedule.items() if times != []} + schedule = [] + for hour, deps in schedule_2.items(): + for dep in deps: + schedule.append((hour, *describe(dep['time'], legends), dep['lowFloor'])) + schedules[mode_name] = schedule + + return schedules, hashlib.sha512(index.text.encode('utf-8')).hexdigest() + + +def describe(dep_time, legend): + """ + describe departure + """ + desc = [] + while re.match('^\\d+$', dep_time) is None: + if dep_time[-1] != ',': + desc.append(legend[dep_time[-1]]) + dep_time = dep_time[:-1] + return (int(dep_time), '; '.join(desc)) + + +def main(): + """ + main function + """ + print(time.time()) + with sqlite3.connect('timetable.db') as connection: + print('creating tables') + cursor = connection.cursor() + cursor.execute('create table nodes(symbol TEXT PRIMARY KEY, name TEXT)') + cursor.execute('create table stops(id TEXT PRIMARY KEY, symbol TEXT \ + references node(symbol), number TEXT, lat REAL, lon REAL, headsigns TEXT)') + cursor.execute('create table lines(id TEXT PRIMARY KEY, number TEXT)') + cursor.execute('create table timetables(id INTEGER PRIMARY KEY, stop_id \ + TEXT references stop(id), line_id TEXT references line(id), \ + headsign TEXT, checksum TEXT)') + cursor.execute('create table departures(id INTEGER PRIMARY KEY, timetable_id INTEGER \ + references timetable(id), hour INTEGER, minute INTEGER, mode TEXT, \ + lowFloor INTEGER, modification TEXT)') + + print('getting nodes') + nodes = get_nodes() + cursor.executemany('insert into nodes values(?, ?);', nodes) + nodes_no = len(nodes) + print('getting stops') + node_i = 1 + for symbol, _ in nodes: + print('\rstop {}/{}'.format(node_i, nodes_no), end='') + sys.stdout.flush() + cursor.executemany('insert into stops values(?, ?, ?, ?, ?, ?);', get_stops(symbol)) + node_i += 1 + print('') + lines = get_lines() + lines_no = len(lines) + line_i = 1 + tti = 0 + cursor.executemany('insert into lines values(?, ?);', lines.items()) + for line_id, _ in lines.items(): + route = get_route(line_id) + routes_no = len(route) + route_i = 1 + for direction, stops in route.items(): + stops_no = len(stops) + stop_i = 1 + for stop in stops: + print('line {}/{} route {}/{} stop {}/{}'. + format(line_i, lines_no, route_i, routes_no, stop_i, stops_no), end='') + sys.stdout.flush() + timetables, checksum = get_stop_times(stop['id'], line_id, direction) + cursor.execute('insert into timetables values(?, ?, ?, ?, ?);', + (tti, stop['id'], line_id, stops[-1]['name'], checksum)) + for mode, times in timetables.items(): + cursor.executemany('insert into departures values(null, ?, ?, ?, ?, ?, ?);', + [(tti, hour, minute, mode, lowfloor, desc) + for hour, minute, desc, lowfloor in times]) + stop_i += 1 + tti += 1 + print('{}\r'.format(' '*35), end='') + sys.stdout.flush() + route_i += 1 + print('') + line_i += 1 + print(time.time()) + + +if __name__ == '__main__': + main() diff --git a/research/timetable.db.xz b/research/timetable.db.xz new file mode 100644 index 0000000000000000000000000000000000000000..a31038b42c82ca61c77af8629de0cfe1f1da28e3 Binary files /dev/null and b/research/timetable.db.xz differ