├── .github
└── ISSUE_TEMPLATE
│ ├── fehlerhafte-datenlisten.md
│ └── neue-datenquelle.md
├── .gitignore
├── .gitmodules
├── .pylintrc
├── AnswerMachine
├── __init__.py
├── candidate.py
├── handle_list.py
├── react.py
└── result.py
├── Documentation
├── __init__.py
├── dump.py
├── dump_il.py
├── generator.py
├── licenses.py
└── markdowndoc.py
├── Externals
├── Measure.py
├── __init__.py
├── database.py
├── mastodon.py
├── message.py
├── network.py
└── user.py
├── Import
├── __init__.py
├── access.py
├── datasource.py
├── error.py
├── row.py
└── sourceconfig.py
├── LICENSE
├── Persistence
├── __init__.py
├── gitdescribe.py
└── since.py
├── README.md
├── cards
├── socialcard.png
└── socialcard.svg
├── config
├── api_weights.json
└── schema.sql
├── data
├── README.md
├── bot.json
├── faq.json
├── linien_bhvbus.json
├── linien_bsag.json
├── linien_by.json
├── linien_dd.json
├── linien_de_fv.json
├── linien_delbus.json
├── linien_ffm.json
├── linien_hg.json
├── linien_koeln.json
├── linien_mv.json
├── linien_ni.json
├── linien_nl.json
├── linien_no.json
├── linien_nvs.json
├── linien_nw.json
├── linien_opr.json
├── linien_p.json
├── linien_rmv.json
├── linien_rnv.json
├── linien_rvf.json
├── linien_sh.json
├── linien_sn.json
├── linien_th.json
├── linien_vab.json
├── linien_vbb.json
├── linien_vvs.json
├── linien_wtv.json
├── orte_at.json
├── orte_be.json
├── orte_ca.json
├── orte_ch.json
├── orte_dd.json
├── orte_de.json
├── orte_dk.json
├── orte_ffm.json
├── orte_fr.json
├── orte_hh.json
├── orte_ibnr.json
├── orte_leitpunkte.json
├── orte_nl.json
├── orte_no.json
├── orte_nvs.json
├── orte_se.json
├── orte_uk.json
├── orte_wien.json
├── regeln_de.json
├── regeln_vkms.json
├── signale_bostrab.json
├── signale_de_ds301.json
├── signale_de_dv301.json
├── signale_de_gemein.json
├── signale_no.json
├── strecken_ch.json
├── strecken_de.json
├── strecken_ffm.json
└── strecken_no.json
├── doc
├── aufbau-antworten.md
├── avatar-bahn.social.svg
├── avatar-ril100.svg
├── avatar-zug.network.svg
├── avatar.svg
├── bot.css
├── contribute.md
├── copyright.md
├── datenschutz.md
├── faq.md
├── finde-lang.md
├── finde-listen.md
├── finde-toots.md
├── haftung.md
├── ignorelist.md
├── impressum.md
├── index.md
├── interaktion.md
├── leerzeichen_ds100.md
├── links.snip
├── mastodon-icon.png
├── motivation.md
├── script.js
└── twitter-icon.png
├── ds100bot
├── get_status
├── sources
├── README.md
├── bot.csv
├── faq.csv
├── linien_bhvbus.csv
├── linien_bsag.csv
├── linien_by.csv
├── linien_dd.csv
├── linien_de_fv.csv
├── linien_delbus.csv
├── linien_ffm.csv
├── linien_hg.csv
├── linien_koeln.csv
├── linien_mv.csv
├── linien_ni.csv
├── linien_nl.csv
├── linien_no.csv
├── linien_nvs.csv
├── linien_nw.csv
├── linien_nwm.csv
├── linien_opr.csv
├── linien_p.csv
├── linien_rmv.csv
├── linien_rnv.csv
├── linien_rvf.csv
├── linien_sh.csv
├── linien_sn.csv
├── linien_th.csv
├── linien_vab_kreis_ab.csv
├── linien_vab_kreis_mb.csv
├── linien_vab_stadt_ab.csv
├── linien_vbb.csv
├── linien_vlp.csv
├── linien_vvs.csv
├── linien_wtv.csv
├── orte_at_db640.csv
├── orte_be.csv
├── orte_ca_via.csv
├── orte_ch_add.csv
├── orte_ch_didok.csv
├── orte_dd.csv
├── orte_de_add.csv
├── orte_de_ds100.csv
├── orte_de_stationsdaten.csv
├── orte_dk.csv
├── orte_ffm.csv
├── orte_hamburg.csv
├── orte_leitpunkte.csv
├── orte_nl.csv
├── orte_no.csv
├── orte_nvs.csv
├── orte_se.csv
├── orte_sncf.csv
├── orte_uk_crs.csv
├── orte_uk_long.csv
├── orte_wien.csv
├── regeln_de.csv
├── regeln_vkms.csv
├── signale_bostrab.csv
├── signale_de.csv
├── signale_de_gemein.csv
├── signale_no.csv
├── strecken_ch_sbb.csv
├── strecken_de_alt.csv
├── strecken_de_kbs.csv
├── strecken_de_namen.csv
├── strecken_de_vzg.csv
├── strecken_ffm.csv
└── strecken_no.csv
├── statistics
├── test
├── tests
├── test_find_tokens.py
├── test_network.py
├── test_process_commands.py
└── test_process_magic.py
└── tools
├── add_score_to_commit_msg
├── check
├── find_all_pys
├── manage-blacklist
├── parentdir.py
└── setup
/.github/ISSUE_TEMPLATE/fehlerhafte-datenlisten.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Fehlerhafte Datenlisten
3 | about: Issue für Datenfehler
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Um welche Datenliste handelt es sich:**
11 | Magic Hashtag + Typ, Explizite Quelle oder Name des Dumps (z.B., #DS100, #DS:, orte_de
12 |
13 | **Fehlt ein Datensatz?**
14 | Abkürzung:
15 | Erwarteter Langtext:
16 |
17 | **Ist ein Datensatz falsch?**
18 | Abkürzung:
19 | Aktueller Langtext laut Bot:
20 | Korrekter Langtext:
21 |
22 | (falls möglich): **URL des Tweet, der falsch beantwortet wurde:**
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/neue-datenquelle.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Neue Datenquelle
3 | about: Vorschläge für neue Datenquellen
4 | title: ''
5 | labels: daten:neu
6 | assignees: ''
7 |
8 | ---
9 |
10 | Vorschlag für neue Datenquelle:
11 | * Art der Quelle (#Orte, $Strecken, %Signale, &Regeln_Sonstiges, /Linien, Typen): […]
12 | * Kurzbeschreibung/Netz (z.B. „Niederländische Signalordnung“, „Japanische Linien“): […]
13 | * Link: […]
14 | * Ich möchte selbst daran arbeiten (Ja/Nein)*: […]
15 | * Die Daten stehen unter/stelle ich unter folgende Lizenz**: […]
16 | * Vorgeschlagenes Kürzel (z.B. 'CH') und Magic Hashtag (z.B. '\_CH'): […]/[…]
17 |
18 | ## Hinweise für Liniennetze:
19 | - Daten sollten nach Liniennetzen sortiert sein – also etwa nach Verkehrsverbünden oder S-Bahn-Netzen.
20 | - Soll ein Datensatz in verschiedenen Liniennetzen auftauchen, sollte der Text dafür identisch sein.
21 | - Der Langtext sollte eine sinnvolle Identifizierung des Linienweges zulassen: Unterwegshaltepunkte sind erlaubt, sollten aber nicht überhand nehmen. Siehe unten zur Länge der Texte.
22 | - Hat eine Linie unterschiedliche Laufwege, sollten diese sinnvoll dargestellt werden.
23 | - Keine zwei Einträge für Hin- und Rückrichtung.
24 |
25 | ## Hinweise für die Bearbeitung:
26 | Bitte die Dokumentation für [Konfigurationen](https://ds100.frankfurtium.de/data.html) und [Datenlisten](https://ds100.frankfurtium.de/sources.html) beachten.
27 |
28 | Ich habe die Regeln verstanden und bin damit einverstanden: […]
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | credentials.py
2 | version.py
3 | __pycache__
4 | info.db
5 | *.html
6 | doc/output
7 | doc/dumps.snip
8 | tweet_details.py
9 | saved_tweets/
10 | sonstiges/
11 |
12 | # Python Virt-Env
13 | env/
14 |
15 | # VSCode/VSCodium
16 | .vscode/
17 |
18 | # IntelliJ
19 | .idea/
20 | *.iml
21 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "GitVersion"]
2 | path = GitVersion
3 | url = git@github.com:baeuchle/gitversion.git
4 |
--------------------------------------------------------------------------------
/AnswerMachine/__init__.py:
--------------------------------------------------------------------------------
1 | """Everything that concerns creating the bot's answers.
2 |
3 | Entrypoint is handle_list::handle_list"""
4 |
5 | from .handle_list import handle_list
6 |
--------------------------------------------------------------------------------
/AnswerMachine/candidate.py:
--------------------------------------------------------------------------------
1 | """Abstracts an abbreviation candidate"""
2 |
3 | class Candidate:
4 | def __init__(self, parts, magic):
5 | if parts[0] is None or parts[0] == '':
6 | self.type_character = '#'
7 | else:
8 | self.type_character = parts[0]
9 | self.explicit_source = parts[1]
10 | self.abbr = parts[2]
11 | self.abbr = self.abbr[0] + self.abbr[1:].replace('_', ' ')
12 | self.abbr = ' '.join(self.abbr.split())
13 | self.magic_hashtag = magic
14 |
15 | def get_dict(self):
16 | return {
17 | 'type_character': self.type_character,
18 | 'explicit_source': self.explicit_source,
19 | 'abbr': self.abbr,
20 | 'magic_hashtag': self.magic_hashtag
21 | }
22 |
23 | def __str__(self):
24 | return str(self.get_dict())
25 |
26 | def __eq__(self, rhs):
27 | return self.__dict__ == rhs.__dict__
28 |
--------------------------------------------------------------------------------
/AnswerMachine/handle_list.py:
--------------------------------------------------------------------------------
1 | # pylint: disable=C0114
2 | import logging
3 | from .react import process_commands, process_message
4 | logger = logging.getLogger('bot.' + __name__)
5 |
6 | def handle_list(network, database, magic_tags, magic_emojis):
7 | message_dict = network.all_relevant_status(magic_tags)
8 | for mid, message in message_dict.items():
9 | # exclude some message:
10 | if message.is_not_eligible:
11 | logger.debug("Status %s is not eligible", mid)
12 | continue
13 | logger.info("Looking at status %d", mid)
14 | # handle #folgenbitte and #entfolgen and possibly other meta commands, but
15 | # only for explicit mentions.
16 | if message.is_explicit_mention:
17 | logger.info("Message explicitly mentions me")
18 | process_commands(message, network)
19 | if message.has_hashtag(magic_tags):
20 | logger.info("Message has magic hashtag")
21 | if message.has_hashtag(magic_emojis):
22 | logger.info("Message has magic emoji")
23 | # Process this message
24 | mode = message.get_mode(magic_tags, magic_emojis)
25 | dmt = message.default_magic_hashtag([*magic_tags, *magic_emojis])
26 | process_message(message,
27 | network,
28 | database,
29 | magic_tags,
30 | magic_emojis,
31 | modus=mode,
32 | default_magic_tag=dmt)
33 | for other in message.get_other_posts(
34 | message_dict,
35 | mode=mode,
36 | network=network,
37 | database=database,
38 | magic_tags=magic_tags,
39 | magic_emojis=magic_emojis
40 | ):
41 | logger.debug("Processing message %d mode %s def magic hash tag %s", other.id, mode, dmt)
42 | process_message(other,
43 | network,
44 | database,
45 | magic_tags,
46 | magic_emojis,
47 | modus=mode,
48 | default_magic_tag=dmt)
49 |
--------------------------------------------------------------------------------
/AnswerMachine/result.py:
--------------------------------------------------------------------------------
1 | """Abstracts the abbreviation search result"""
2 |
3 | import logging
4 | logger = logging.getLogger('bot.' + __name__)
5 |
6 | class Result:
7 | # pylint: disable=R0902
8 | def __init__(self, candidate, db):
9 | self.candidate = candidate
10 | row = self.find_in_db(db.cursor)
11 | self.abbr = candidate.abbr
12 | if row is not None:
13 | self.long = row['name']
14 | self.status = row['status']
15 | self.source = row['req_xs']
16 | self.type = row['req_tc']
17 | self.default_source = row['def_xs']
18 | self.default_type = row['def_tc']
19 | else:
20 | self.long = ''
21 | self.status = 'notfound'
22 | self.source = ''
23 | self.type = candidate.type_character
24 | self.default_source = ''
25 | self.default_type = ''
26 | logger.debug("%s → %s", candidate, self)
27 |
28 | def __str__(self):
29 | if self.status == 'notfound':
30 | return 'None'
31 | return self.normalized() + '::' + self.long
32 |
33 | def normalized(self):
34 | if self.status == 'notfound':
35 | return None
36 | return '{}{}:{}'.format(self.type, self.default_source, self.abbr)
37 |
38 | def answered(self):
39 | text = '{}: {}\u200b\n'.format(self.abbr, self.long)
40 | if not (self.default_source == 'DS' or self.source == 'BOT'):
41 | text = '{}{}{}'.format(self.source, self.type, text)
42 | return text.replace('\\n', '\n')
43 |
44 | def find_in_db(self, sql):
45 | sql.execute("""
46 | SELECT
47 | shortstore.Abk as abk,
48 | shortstore.Name AS name,
49 | s1.explicit_source AS req_xs,
50 | s1.type AS req_tc,
51 | s2.explicit_source AS def_xs,
52 | s2.type AS def_tc,
53 | CASE
54 | WHEN (
55 | blacklist.Abk IS NOT NULL
56 | AND
57 | :explicit_source = ''
58 | ) THEN 'blacklist'
59 | ELSE 'found'
60 | END
61 | AS status
62 | FROM
63 | shortstore
64 | JOIN sources AS s1 ON s1.source_id = shortstore.source
65 | JOIN sources AS s2 ON s1.source_id = s2.source_id
66 | JOIN magic_hashtags ON magic_hashtags.source_id = shortstore.source
67 | LEFT OUTER JOIN blacklist ON blacklist.Abk = shortstore.Abk AND s1.type = '#'
68 | WHERE
69 | shortstore.Abk = :abbr
70 | AND s1.type = :type_character
71 | AND (
72 | (:explicit_source != '' AND s1.explicit_source = :explicit_source)
73 | OR
74 | (:explicit_source == ''
75 | AND (magic_hashtags.magic_hashtag = :magic_hashtag
76 | OR s1.explicit_source = 'BOT'
77 | )
78 | ))
79 | AND s2.is_default
80 | """,
81 | self.candidate.get_dict()
82 | )
83 | result = sql.fetchall()
84 | if not result:
85 | return None
86 | if len(result) == 1:
87 | return result[0]
88 | # if more than one: BOT has *no* precedence.
89 | for row in result:
90 | if row['req_xs'] != 'BOT':
91 | return row
92 | return result[0]
93 |
94 | def loggable(self, magic_tags):
95 | if self.status in ('found', 'blacklist'):
96 | return True
97 | if self.candidate.explicit_source != '':
98 | return True
99 | if len(self.abbr) == 0 or len(self.abbr) > 5:
100 | return False
101 | if '#' + self.abbr in magic_tags:
102 | return False
103 | return True
104 |
--------------------------------------------------------------------------------
/Documentation/__init__.py:
--------------------------------------------------------------------------------
1 | """Collects everything for the successful creation of HTML Documentation"""
2 |
3 | from xml.etree import ElementTree as ET
4 | from pathlib import Path
5 | from .generator import Generator
6 | from .dump import Dump
7 | from .dump_il import DumpIgnorelist
8 | from .markdowndoc import MarkdownDoc
9 | from .licenses import Licenses
10 |
11 | def create_documentation(navi_list, md_dir, html_dir):
12 | for mdfile in md_dir.glob('*.md'):
13 | # don't consider copyright.md:
14 | if mdfile.stem == 'copyright':
15 | continue
16 | dp = MarkdownDoc(mdfile, navi_list)
17 | dp.write(html_dir / (mdfile.stem + '.html'))
18 |
19 | def dumplink_list(config_list):
20 | div = ET.Element('div', attrib={'class': 'dumpnavi hiddennavi'})
21 | ET.SubElement(div, 'div', attrib={'class': 'closenavi'},
22 | onclick="toggle_any('dumpnavi')").text = "Alle Dumps"
23 | linklist = ET.SubElement(div, 'ul')
24 | sublists = {}
25 | sigils = {'#': 'Orte',
26 | '$': 'Strecken',
27 | '/': 'Linien',
28 | '%': 'Signale',
29 | '&': 'Regeln'
30 | }
31 | for sigil, sigilname in sigils.items():
32 | sublists[sigil] = ET.Element('ul', attrib={'class': f'dump_{sigilname.lower()}'})
33 | for cid, conf in sorted(config_list.items()):
34 | item = ET.Element('li')
35 | ET.SubElement(item, 'a', attrib={'href': '/dumps/' + cid + '.html'}).text = conf.head
36 | if len(conf.file.stem) > 5:
37 | inserted_once = False
38 | for sigil in set(x.type for x in conf.access):
39 | if sigil in sublists:
40 | sublists[sigil].append(item)
41 | inserted_once = True
42 | if inserted_once:
43 | continue
44 | # Fallthrough from the above: 5 letters or less or unknown sigil.
45 | linklist.append(item)
46 | for sigil, subl in sublists.items():
47 | classname = f'dump_{sigils[sigil].lower()}'
48 | sublistitem = ET.SubElement(linklist, 'li', attrib={'class': f'{classname} hiddennavi'})
49 | listhl = ET.SubElement(sublistitem, 'div', onclick=f"toggle_any('{classname}')")
50 | ET.SubElement(listhl, 'span', attrib={'class': 'sigil'}).text = sigil
51 | ET.SubElement(listhl, 'span').text = sigils[sigil]
52 | sublistitem.append(subl)
53 | item = ET.SubElement(linklist, 'li')
54 | ET.SubElement(item, 'a', attrib={'href': '/dumps/ignorelist.html'}).text = 'Blacklist'
55 | return div
56 |
57 | def navilink_list(version):
58 | linkroot = ET.parse('doc/links.snip').getroot()
59 | for vtag in linkroot.findall(".//li[@class='transform_version']"):
60 | vtag.text = "Version: {}".format(version)
61 | return linkroot
62 |
63 | def create_dump_mainpage(navi, dump, dumpdir):
64 | mp = Generator('DS100-Daten-Dump Liste', links=navi)
65 | mp.headline('Liste der Datenquellen')
66 | dl = ET.SubElement(mp.main, 'navi')
67 | # We will manipulate dump, so we have to copy it first.
68 | # This is the only way I can find.
69 | dl.append(ET.fromstring(ET.tostring(dump)))
70 | dl.find('./div').set('class', 'bigdumplist')
71 | mp.write(dumpdir / 'index.html')
72 |
73 | def dump_source(config, dumplinks, navilinks, db, dumpdir):
74 | dump = Dump('DS100-Daten-Dump', config, dumplinks=dumplinks, links=navilinks)
75 | for entry_row in db.dumplist(config.id):
76 | dump.add_row(entry_row)
77 | dump.write(dumpdir / (config.id + '.html'))
78 |
79 | def dump_ignorelist(dumplinks, navilinks, db, dumpdir):
80 | dump = DumpIgnorelist(dumplinks=dumplinks, links=navilinks)
81 | for entry_row in db.dumpblack():
82 | dump.add_row(entry_row)
83 | dump.write(dumpdir / 'ignorelist.html')
84 |
--------------------------------------------------------------------------------
/Documentation/dump_il.py:
--------------------------------------------------------------------------------
1 | """Creates the dump of the Ignorelist"""
2 |
3 | from xml.etree import ElementTree as ET
4 | from .dump import Dump
5 | from .generator import Generator
6 |
7 | class DumpIgnorelist(Dump):
8 | def __init__(self, **kwargs):
9 | # pylint: disable=W0233
10 | Generator.__init__(self,
11 | 'DS100-Daten-Dump Ignorelist',
12 | desc='Alle Kürzel, die wegen anderer Bedeutungen normalerweise ignoriert werden',
13 | **kwargs)
14 | self.headline("Ignorelist")
15 | ET.SubElement(self.head, 'p').text = """Die folgenden Einträge werden nicht ohne explizite
16 | Quellenangabe (z.B. "#DS:") beantwortet."""
17 | self.head.append(kwargs.get('dumplinks', None))
18 | self.table = ET.SubElement(self.main, 'table', attrib={'class': 'dumptable'})
19 | links = kwargs.get('links', None)
20 | if links is not None:
21 | self.head.append(links)
22 | self.number_of_data_lists = 2
23 |
--------------------------------------------------------------------------------
/Documentation/generator.py:
--------------------------------------------------------------------------------
1 | """Base class for all HTML documentation generators"""
2 |
3 | from xml.etree import ElementTree as ET
4 |
5 | class Generator:
6 | SITENAME = {'property': 'og:site_name', 'content': 'DS100 Bot'}
7 | CARD = {'content': 'https://ds100.frankfurtium.de/socialcard.png'}
8 | LOCALE = {'property': 'og:locale', 'content': 'de_DE'}
9 | CARDTYPE = {'name': 'twitter:card', 'content': 'summary_large_image'}
10 | SITE = {'name': 'twitter:site', 'content': '@_ds_100'}
11 | CREATOR = {'name': 'twitter:creator', 'content': '@baeuchle'}
12 | def __init__(self, titletext, **kwargs):
13 | self.html = ET.Element('html', attrib={'prefix': 'og: https://ogp.me/ns#'})
14 | head = ET.SubElement(self.html, 'head')
15 | head.append(ET.Element('meta', attrib={'charset': 'utf-8'}))
16 | head.append(ET.Element('meta', attrib={
17 | 'name': 'viewport',
18 | 'content': 'width=device-width, initial-scale=1.0'
19 | }))
20 | head.append(ET.Element('link', attrib={
21 | 'rel': 'stylesheet',
22 | 'type': 'text/css',
23 | 'href': '/bot.css'
24 | }))
25 | head.append(ET.Element('link', attrib={
26 | 'rel': 'shortcut icon',
27 | 'type': 'image/svg+xml',
28 | 'href': 'https://avatar.frankfurtium.de/ds100.svg'
29 | }))
30 | ET.SubElement(head, 'script', attrib={
31 | 'type': 'text/javascript',
32 | 'src': '/script.js'
33 | }).text = " "
34 | desc = {'content': kwargs.get('desc', titletext)}
35 | head.append(ET.Element('meta', attrib={'property': 'og:title', 'content': titletext}))
36 | head.append(ET.Element('meta', attrib=Generator.SITENAME))
37 | head.append(ET.Element('meta', attrib={'property': 'og:image', **Generator.CARD}))
38 | head.append(ET.Element('meta', attrib={'property': 'og:description', **desc}))
39 | head.append(ET.Element('meta', attrib=Generator.LOCALE))
40 | head.append(ET.Element('meta', attrib=Generator.CARDTYPE))
41 | head.append(ET.Element('meta', attrib={'name': 'twitter:title', 'content': titletext}))
42 | head.append(ET.Element('meta', attrib={'name': 'twitter:description', **desc}))
43 | head.append(ET.Element('meta', attrib=Generator.SITE))
44 | head.append(ET.Element('meta', attrib=Generator.CREATOR))
45 | head.append(ET.Element('meta', attrib={'name': 'twitter:image', **Generator.CARD}))
46 | head.append(ET.Element('meta', attrib={'name': 'description', **desc}))
47 | title = ET.SubElement(head, 'title')
48 | title.text = titletext
49 | body = ET.SubElement(self.html, 'body')
50 | self.head = ET.SubElement(body, 'header')
51 | self.main = ET.SubElement(body, 'main')
52 | self.foot = ET.SubElement(body, 'footer')
53 | self.navi = ET.SubElement(self.foot, 'navi')
54 | ET.SubElement(self.navi, 'p', onclick="toggle_menu()").text = 'Menü'
55 | if 'links' in kwargs:
56 | self.navi.append(kwargs['links'])
57 |
58 | def headline(self, titletext):
59 | ET.SubElement(self.head, 'h1').text = titletext
60 | self.navi_in_head()
61 |
62 | def navi_in_head(self):
63 | navi = ET.SubElement(self.head, 'navi')
64 | ET.SubElement(navi, 'p', onclick="toggle_menu()").text = 'Menü'
65 |
66 | def write(self, targetfile):
67 | with targetfile.open(mode='w') as tf:
68 | ET.ElementTree(self.html).write(tf,
69 | encoding='unicode', method='xml')
70 |
71 | @classmethod
72 | def xmltext(cls, text):
73 | return ET.fromstring('' + text + ' ')
74 |
--------------------------------------------------------------------------------
/Documentation/licenses.py:
--------------------------------------------------------------------------------
1 | """Generates the copyright file with license information"""
2 |
3 | from xml.etree import ElementTree as ET
4 | from .markdowndoc import MarkdownDoc
5 | from .generator import Generator
6 |
7 | class Licenses(MarkdownDoc):
8 | def __init__(self, mdfile, navi):
9 | super().__init__(mdfile, navi)
10 | self.add_table('Nach id sortiert')
11 |
12 | def add_table(self, headline):
13 | lic_table = ET.SubElement(self.main, 'table')
14 | if headline:
15 | ET.SubElement(lic_table, 'caption').text = headline
16 | thead = ET.SubElement(lic_table, 'thead')
17 | tr = ET.SubElement(thead, 'tr')
18 | for text in ('', 'Beschreibung',
19 | 'Dump', 'Magic Hashtag / Magic emoji'):
20 | th = ET.SubElement(tr, 'th')
21 | th.text = text
22 | self.lic = ET.SubElement(lic_table, 'tbody')
23 |
24 | def add_source(self, source):
25 | tr = ET.SubElement(self.lic, 'tr')
26 | ET.SubElement(tr, 'th').text = ', '.join(
27 | set('{}{}:'.format(a.type, a.explicit_source) for a in source.access)
28 | )
29 | if source.desc:
30 | ET.SubElement(tr, 'td').append(Generator.xmltext(source.desc))
31 | else:
32 | ET.SubElement(tr, 'td').text = source.head
33 | dump_container = ET.SubElement(tr, 'td')
34 | ET.SubElement(dump_container, 'a', attrib={
35 | 'href': '/dumps/' + source.id + '.html'
36 | }).text = source.id
37 | mht_container = ET.SubElement(tr, 'td')
38 | mht_container.text = ', '.join(source.magic_hashtags)
39 | if source.id == 'bot':
40 | mht_container.text = 'N/A'
41 |
--------------------------------------------------------------------------------
/Documentation/markdowndoc.py:
--------------------------------------------------------------------------------
1 | """Generates an arbitrary HTML documentation file from a Markdown file"""
2 |
3 | from xml.etree import ElementTree as ET
4 | import markdown
5 | from .generator import Generator
6 |
7 | class MarkdownDoc(Generator):
8 | def __init__(self, mdfile, navi):
9 | with mdfile.open() as mdin:
10 | self.md = mdin.read()
11 | # wrap in so that the XML parser is satisfied
12 | hypertext = '{} '.format(markdown.markdown(self.md))
13 | generator_kwargs = {'links': navi}
14 | xmltree = ET.fromstring(hypertext)
15 | hl = xmltree.find('./h1')
16 | title = '@_ds_100'
17 | if hl is not None:
18 | title += ': ' + hl.text
19 | # title is overridden by p[@id=meta]/title:
20 | meta = xmltree.find('p[@id="meta"]')
21 | if meta:
22 | xmltree.remove(meta)
23 | titletag = meta.find('./title')
24 | if titletag is not None:
25 | title = titletag.text
26 | desc = meta.find('./desc')
27 | if desc is not None:
28 | generator_kwargs['desc'] = desc.text
29 | super().__init__(title, **generator_kwargs)
30 | self.head.append(hl)
31 | self.navi_in_head()
32 | for tag in xmltree:
33 | if tag.tag == 'h1':
34 | continue
35 | self.main.append(tag)
36 |
--------------------------------------------------------------------------------
/Externals/__init__.py:
--------------------------------------------------------------------------------
1 | """External APIs"""
2 |
3 | from .database import setup_database
4 | from .network import set_arguments
5 | from .network import test_network_arguments
6 | from .network import Network
7 | from .mastodon import make_mastodon
8 |
9 | def setup_network(_, args, highest_ids):
10 | return make_mastodon(args, highest_ids)
11 |
--------------------------------------------------------------------------------
/Externals/user.py:
--------------------------------------------------------------------------------
1 | """Abstraction of social media users"""
2 |
3 | from urllib.parse import urlparse
4 |
5 | class User:
6 | def __init__(self, name, uid, host):
7 | self._name = name
8 | self._id = uid
9 | self._host = host
10 |
11 | @property
12 | def host(self):
13 | return self._host
14 |
15 | def __str__(self):
16 | return self._name
17 |
18 | def __int__(self):
19 | return self._id
20 |
21 | def __eq__(self, rhs):
22 | return str(self) == str(rhs)
23 |
24 | def fromTwitterUser(twuser):
25 | return User(twuser.screen_name, twuser.id, 'twitter.com')
26 |
27 | def fromMastodonUser(mastuser):
28 | authorurl = urlparse(mastuser.url)
29 | return User(mastuser.acct, mastuser.id, authorurl.hostname)
30 |
--------------------------------------------------------------------------------
/Import/__init__.py:
--------------------------------------------------------------------------------
1 | """Importing data from JSON/CSV into Database"""
2 |
3 | import logging
4 | from .sourceconfig import SourceConfig
5 | from .error import SourceError, JsonError, DataError
6 |
7 | log_ = logging.getLogger('setup.' + __name__)
8 |
9 | def find_all_configs(directory):
10 | configurations = {}
11 | data_lists = {}
12 | for f in directory.glob('*.json'):
13 | config = None
14 | try:
15 | config = SourceConfig(f)
16 | except SourceError as se:
17 | log_.critical("Error reading configuation file %s: %s", f, str(se))
18 | return None
19 | if config.id in configurations:
20 | log_.critical("Source %s specified twice: in %s and in %s",
21 | config.id, configurations[config.id].file, f)
22 | return None
23 | for dl in config.data_list:
24 | if dl.id in data_lists:
25 | log_.critical("Data list %s specified twice: in %s and in %s",
26 | dl.id, data_lists[dl.id], f)
27 | return None
28 | data_lists[dl.id] = config.file
29 | configurations[config.id] = config
30 | return configurations
31 |
--------------------------------------------------------------------------------
/Import/access.py:
--------------------------------------------------------------------------------
1 | """Abstracts the source access information (explicit source and magic hashtag)"""
2 |
3 | import logging
4 | from .error import JsonError
5 | log_ = logging.getLogger('setup.' + __name__)
6 |
7 | class Access:
8 | # pylint: disable=R0903
9 | _mandatory_fields = (
10 | 'type',
11 | 'x_source'
12 | )
13 |
14 | def __init__(self, config_dict):
15 | self.conf = config_dict
16 | for mf in Access._mandatory_fields:
17 | if mf not in config_dict:
18 | msg = "Key access::{} missing".format(mf)
19 | raise JsonError(msg)
20 | self.type = self.conf['type']
21 | self.explicit_source = self.conf['x_source']
22 |
--------------------------------------------------------------------------------
/Import/datasource.py:
--------------------------------------------------------------------------------
1 | """Abstracts a data source configuration"""
2 |
3 | import csv
4 | import logging
5 | from .error import DataError, JsonError
6 | from .row import Row
7 |
8 | log_ = logging.getLogger('setup.' + __name__)
9 |
10 | class DataSource:
11 | _mandatory_fields = (
12 | "file",
13 | "long",
14 | "short",
15 | "source"
16 | )
17 |
18 | def __init__(self, config_dict, complete_dict):
19 | self.config = config_dict
20 | self.id = self.config.get('id', complete_dict.get('id', None))
21 | for mf in DataSource._mandatory_fields:
22 | if mf not in config_dict:
23 | msg = "Key {} missing".format(mf)
24 | raise JsonError(msg)
25 | if self.id is None:
26 | raise JsonError("Key id neither in top level nor data::id")
27 | handle = open(self.config['file'], encoding='utf-8') # pylint: disable=consider-using-with
28 | self.reader = csv.DictReader(handle, delimiter=self.config.get('delim', ';'))
29 | self.cols = {
30 | 'short': self.config['short'],
31 | 'long': self.config['long'],
32 | 'add': self.config.get('add', None)
33 | }
34 | self.iter = {
35 | 'iter': None, # iterator
36 | 'split': self.config.get('alias', None), # split character for aliases
37 | 'index': 0, # split array index
38 | 'next': None # next item
39 | }
40 | self.nolink = self.config.get('nolink', False)
41 | self.filters = self.config.get('filter', [])
42 |
43 | def __iter__(self):
44 | self.iter['iter'] = self.reader.__iter__()
45 | return self
46 |
47 | def __next__(self):
48 | row = None
49 | while True:
50 | if self.iter['index'] == 0:
51 | self.iter['next'] = self.iter['iter'].__next__()
52 | try:
53 | row = Row(self.iter, self.cols, self.nolink, self.filters)
54 | if row.valid:
55 | self.iter['index'] = row.next_index()
56 | break
57 | self.iter['index'] = 0
58 | except DataError as de:
59 | de.args = ['{}: {}'.format(self.getPosition(), de.args[0])]
60 | raise
61 | return row
62 |
63 | def getLineNum(self):
64 | return self.reader.line_num
65 |
66 | def getPosition(self):
67 | return "{}::{}".format(self.config['file'], self.line_num)
68 |
69 | line_num = property(getLineNum)
70 | position = property(getPosition)
71 |
--------------------------------------------------------------------------------
/Import/error.py:
--------------------------------------------------------------------------------
1 | """Exception classes for imports"""
2 |
3 | class SourceError(Exception):
4 | pass
5 |
6 | class JsonError(SourceError):
7 | pass
8 |
9 | class DataError(SourceError):
10 | pass
11 |
--------------------------------------------------------------------------------
/Import/row.py:
--------------------------------------------------------------------------------
1 | """Represents a row of abbreviation data"""
2 |
3 | from AnswerMachine.react import find_tokens
4 | from .error import DataError
5 |
6 | class Row:
7 | def normalize(self, contents, col):
8 | try:
9 | return ' '.join(contents[self.cols[col]].split())
10 | except AttributeError as ae:
11 | raise DataError(str(ae)) from ae
12 |
13 | # pylint: disable=R0903
14 | def __init__(self, iterator, cols, nolink, filters):
15 | self.cols = cols
16 | for c in ('short', 'long'):
17 | if self.cols[c] not in iterator['next']:
18 | msg = "Column {} ({}) not in contents".format(self.cols[c], c)
19 | raise DataError(msg)
20 | self.abbr = self.split(iterator)
21 | self.long = self.normalize(iterator['next'], 'long')
22 | self.add = None
23 | if self.cols['add'] is not None and self.cols['add'] in iterator['next']:
24 | self.add = iterator['next'][self.cols['add']]
25 | if nolink:
26 | self.long = self.long.replace('.', '\u2024')
27 | self.valid = False
28 | if self.abbr == "":
29 | return # invalid
30 | self.apply_filters(filters, iterator['next'])
31 | if self.valid:
32 | self.check_abbreviation()
33 |
34 | def apply_filters(self, filters, data):
35 | self.filters = filters
36 | if len(self.filters) == 0:
37 | # no filters: everything valid
38 | self.valid = True
39 | for f in self.filters:
40 | if f['col'] not in data:
41 | self.valid = False
42 | continue
43 | string = data[f['col']]
44 | if (string is None) == f['empty']:
45 | self.valid = True
46 | continue
47 | if (string == "") == f['empty']:
48 | self.valid = True
49 | continue
50 | if f['contains'] in string:
51 | self.valid = True
52 | continue
53 |
54 | def split(self, iterator):
55 | short = self.normalize(iterator['next'], 'short')
56 | if iterator['split'] is not None:
57 | abbrs = short.split(iterator['split'])
58 | short = abbrs[iterator['index']]
59 | self.abbr_index = iterator['index'] + 1
60 | if self.abbr_index == len(abbrs):
61 | self.abbr_index = 0
62 | else:
63 | self.abbr_index = 0
64 | return short
65 |
66 | def check_abbreviation(self):
67 | candidates = find_tokens('#' + self.abbr.replace(' ', '_'), '', '')
68 | if len(candidates) != 1:
69 | self.valid = False
70 | msg = "Abbreviation {} will not be matched".format(self.abbr)
71 | raise DataError(msg)
72 | if candidates[0].abbr != self.abbr:
73 | self.valid = False
74 | msg = "Abbreviation {} will be falsely matched as {}".format(self.abbr,
75 | candidates[0].abbr)
76 | raise DataError(msg)
77 |
78 | def next_index(self):
79 | return self.abbr_index
80 |
81 | def __str__(self):
82 | return str(self.__dict__)
83 |
--------------------------------------------------------------------------------
/Import/sourceconfig.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | """Read source configuation"""
4 |
5 | import json
6 | import logging
7 | from .access import Access
8 | from .datasource import DataSource
9 | from .error import JsonError
10 | log_ = logging.getLogger('setup.' + __name__)
11 |
12 | class SourceConfig:
13 | # pylint: disable=R0903
14 | # pylint: disable=R0902
15 | _mandatory_fields = (
16 | 'access',
17 | 'data',
18 | 'id',
19 | 'magic_hashtags'
20 | )
21 |
22 | def __init__(self, filepath):
23 | self.file = filepath
24 | with self.file.open() as jsonfile:
25 | try:
26 | self.json = json.load(jsonfile)
27 | except json.JSONDecodeError as jde:
28 | msg = "{}::{}::{}: JSON object could not be decoded: {}".format(
29 | self.file, jde.lineno, jde.colno, jde.msg)
30 | raise JsonError(msg) from jde
31 | for mf in SourceConfig._mandatory_fields:
32 | if mf not in self.json:
33 | msg = "Key {} missing".format(mf)
34 | raise JsonError(msg)
35 | self.access = [Access(a) for a in self.json['access']]
36 | self.magic_hashtags = self.json['magic_hashtags']
37 | self.data_list = [DataSource(d, self.json) for d in self.json['data']]
38 | self.id = self.json['id']
39 | self.head = self.json.get("headline", self.json.get("description", self.id))
40 | self.desc = self.json.get("description", "")
41 |
--------------------------------------------------------------------------------
/Persistence/__init__.py:
--------------------------------------------------------------------------------
1 | """This module contains all functions that make the bot remember things"""
2 |
3 | import logging
4 |
5 | from .gitdescribe import notify_new_version, store_version
6 | from .since import store_since_id, get_since_id
7 |
8 | def init_logger(name='bot'):
9 | logger = logging.getLogger(name)
10 | botformat = logging.Formatter(
11 | fmt="%(levelname)-8s %(name)s %(message)s"
12 | )
13 | streamhdl = logging.StreamHandler()
14 | streamhdl.setFormatter(botformat)
15 | logger.addHandler(streamhdl)
16 | return logger
17 |
18 | def set_logging_args(parser, default_lvl='CRITICAL'):
19 | levels = "DEBUG INFO WARNING ERROR CRITICAL".split()
20 | parser.add_argument('--log-level',
21 | help='Set logging level',
22 | required=False,
23 | default=default_lvl,
24 | choices=levels)
25 |
--------------------------------------------------------------------------------
/Persistence/gitdescribe.py:
--------------------------------------------------------------------------------
1 | # pylint: disable=C0114
2 |
3 | import logging
4 |
5 | from GitVersion import Git
6 |
7 | logger = logging.getLogger('bot.persistence')
8 |
9 | git_object = Git()
10 | def get_last_hash(sql):
11 | sql.cursor.execute("""
12 | SELECT
13 | content
14 | FROM
15 | last
16 | WHERE
17 | subject = 'githash'
18 | AND
19 | network = ?
20 | """, (sql.network, ))
21 | row = sql.cursor.fetchone()
22 | if row is None:
23 | return None
24 | return row[0]
25 |
26 | def is_same_version(sql):
27 | return get_last_hash(sql) == git_object.hash()
28 |
29 | def store_version(sql):
30 | for subj, cont in (
31 | ('gitdescribe', git_object.describe()),
32 | ('githash', git_object.hash())
33 | ):
34 | # store last answer time
35 | sql.cursor.execute("""
36 | UPDATE
37 | last
38 | SET
39 | content = ?
40 | WHERE
41 | subject = ?
42 | AND
43 | network = ?
44 | """,
45 | (
46 | cont, subj, sql.network,
47 | )
48 | )
49 | sql.commit()
50 |
51 | def get_changelog(sqlcursor):
52 | last_hash = get_last_hash(sqlcursor)
53 | return git_object.changelog(last_hash).replace('•', '\u200b•')
54 |
55 | def notify_new_version(twitter, database):
56 | if is_same_version(database):
57 | if logger.isEnabledFor(logging.DEBUG):
58 | logger.debug("Using same version as last time: %s", git_object.describe())
59 | return
60 | status = f"Ich schreibe nun von Version {git_object.describe()}"
61 | cl = get_changelog(database)
62 | if cl.strip() != "":
63 | status += ":\n" + cl
64 | if twitter.post(status):
65 | store_version(database)
66 |
--------------------------------------------------------------------------------
/Persistence/since.py:
--------------------------------------------------------------------------------
1 | """
2 | Functions for reading and storing highest ids
3 | """
4 |
5 | import logging
6 |
7 | logger = logging.getLogger('bot.persistence')
8 |
9 | def get_since_id(sql):
10 | sql.cursor.execute("""
11 | SELECT
12 | subject,
13 | content
14 | FROM
15 | last
16 | WHERE
17 | subject IN ('since_id', 'since_notification')
18 | AND
19 | network = ?
20 | """, (sql.network, ))
21 | result = dict(sql.cursor.fetchall())
22 | logger.debug("found highest ids for %s: %s", sql.network, result)
23 | return result
24 |
25 | def store_since_id(sql, network):
26 | id_list = {'since_id': network.high_message}
27 | try:
28 | id_list['since_notification'] = network.high_notification
29 | except AttributeError:
30 | pass
31 | logger.info("storing highest msg id for %s: %s", sql.network, id_list)
32 | # store last answer time
33 | for name, high in id_list.items():
34 | sql.cursor.execute("""
35 | UPDATE
36 | last
37 | SET
38 | content = ?
39 | WHERE
40 | subject = ?
41 | AND
42 | network = ?
43 | """,
44 | (
45 | high,
46 | name,
47 | sql.network,
48 | )
49 | )
50 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | DS-100-Bot
2 | ==========
3 |
4 | Dies ist ein SocialMedia-Bot zur Expansion von Bahnabkürzungen. Aktuell
5 | können sowohl Twitter als aus Mastodon damit bespielt werden.
6 |
7 | Vorbereitungen
8 | --------------
9 |
10 | Die Datei config/schema.sql enthält die Struktur der Datenbank. Die
11 | Datenbank ``info.db`` kann damit erstelt werden:
12 |
13 | ```
14 | cat schema.sql | sqlite3 info.db
15 | ```
16 |
17 | Um den Twitter-Bot nutzen zu können, muss die geneigte Benutzerin
18 | [Twitter-Developress](https://developer.twitter.com/) werden. Dann
19 | erhält sie auch Authentifizierungsdaten.
20 |
21 | Die Datei credentials.py.dist muss in credentials.py umbenannt werden
22 | und die Twitter-Authentifizierungsdaten eingetragen werden.
23 |
24 | Daten werden eingelesen und die Dokumentation erzeugt mit
25 |
26 | ```
27 | tools/setup
28 | ```
29 |
30 | Vorbedinungen
31 | -------------
32 |
33 | Der Bot ist in python3 geschrieben und benutzt SQLite3 als Datenbank.
34 | Alle verwendeten Python-Packages sind als Ubuntu-Packages verfügbar und
35 | wahrscheinlich auch mit pip installierbar.
36 |
37 | Ausführen
38 | ---------
39 |
40 | Es gibt vier Hauptprogramme. Für Informationen zur Bedienung dieser
41 | Programme kann die Option ``--help`` verwendet werden.
42 |
43 | * ``ds100bot``: Der eigentliche Bot. Kann beliebig oft im Abstand weniger
44 | Minuten ausgeführt werden.
45 | * ``statistics``: Gibt Statistiken über die Benutzung des Bots aus. Sollte
46 | z.B. einmal monatlich ausgeführt werden.
47 | * ``test``: Führt Testfälle aus und überprüft, ob die Testtweets korrekt
48 | beantwortet werden.
49 | * ``get_tweet``: Lädt echte Tweets herunter. Damit können problematische
50 | Tweets genauer analysiert werden.
51 |
52 | LIZENZ
53 | ======
54 |
55 | Der Quellcode dieses Bots ist unter der Apache Lizenz, Version 2.0,
56 | lizensiert. Siehe Datei LICENSE.
57 |
58 | Die Datei ``config/api_weights.json`` ist von
59 | https://github.com/twitter/twitter-text/tree/master/config/v3.json
60 | genommen und von Twitter, Inc. ebenfalls unter Apache Lizenz, Version
61 | 2.0, lizensiert.
62 |
63 | Die Datentabellen in ``sources`` stehen unter verschiedenen Lizenzen.
64 | Diese sind in ``data`` aufgeführt.
65 |
--------------------------------------------------------------------------------
/cards/socialcard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baeuchle/ds100bot/1a76be55a87de7793e37ea25d248d1d904843e11/cards/socialcard.png
--------------------------------------------------------------------------------
/config/api_weights.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "maxWeightedTweetLength": 280,
4 | "scale": 100,
5 | "defaultWeight": 200,
6 | "emojiParsingEnabled": true,
7 | "transformedURLLength": 23,
8 | "ranges": [
9 | {
10 | "start": 0,
11 | "end": 4351,
12 | "weight": 100
13 | },
14 | {
15 | "start": 8192,
16 | "end": 8205,
17 | "weight": 100
18 | },
19 | {
20 | "start": 8208,
21 | "end": 8223,
22 | "weight": 100
23 | },
24 | {
25 | "start": 8242,
26 | "end": 8247,
27 | "weight": 100
28 | }
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/config/schema.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE IF NOT EXISTS "last" (
2 | `subject` TEXT NOT NULL,
3 | `content` TEXT,
4 | `network` TEXT NOT NULL
5 | );
6 | CREATE TABLE IF NOT EXISTS "shortstore" (
7 | `id` TEXT NOT NULL,
8 | `Abk` TEXT NOT NULL,
9 | `Name` TEXT NOT NULL,
10 | `Kurzname` TEXT,
11 | `Datenliste` TEXT,
12 | `source` TEXT,
13 | PRIMARY KEY(`id`)
14 | );
15 | CREATE TABLE IF NOT EXISTS "sources" (
16 | "source_id" TEXT NOT NULL,
17 | "type" TEXT,
18 | "explicit_source" TEXT NOT NULL,
19 | "is_default" INTEGER NOT NULL DEFAULT 0 CHECK(is_default in (0,1))
20 | );
21 | CREATE TABLE IF NOT EXISTS "magic_hashtags" (
22 | "source_id" TEXT NOT NULL,
23 | "magic_hashtag" TEXT NOT NULL
24 | );
25 | CREATE TABLE IF NOT EXISTS "blacklist" (
26 | `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
27 | `source` TEXT NOT NULL,
28 | `Abk` TEXT NOT NULL
29 | );
30 | CREATE TABLE "requestlog" (
31 | "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
32 | "explicit_source" TEXT,
33 | "active_magic" TEXT NOT NULL,
34 | "type" TEXT,
35 | "abbreviation" TEXT NOT NULL,
36 | "request_date" TEXT NOT NULL,
37 | "derived_source" TEXT NOT NULL,
38 | "status" TEXT NOT NULL,
39 | "network" TEXT NOT NULL
40 | );
41 |
--------------------------------------------------------------------------------
/data/bot.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "bot",
3 | "headline": "Informationen über den Bot",
4 | "access": [{
5 | "x_source": "BOT",
6 | "type": "#"
7 | }],
8 | "magic_hashtags": [
9 | "BOTINFO"
10 | ],
11 | "data": [{
12 | "id": "bot",
13 | "short": "Abk",
14 | "long": "Name",
15 | "alias": ",",
16 | "file": "sources/bot.csv",
17 | "source": {
18 | "name": "Eigene Zusammenstellung"
19 | }
20 | }]
21 | }
22 |
--------------------------------------------------------------------------------
/data/faq.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "faq",
3 | "headline": "FAQs",
4 | "access": [{
5 | "x_source": "FAQ",
6 | "type": "#"
7 | }],
8 | "magic_hashtags": [
9 | "BOTFAQ"
10 | ],
11 | "data": [{
12 | "id": "faq",
13 | "short": "Abk",
14 | "long": "Name",
15 | "file": "sources/faq.csv",
16 | "source": {
17 | "name": "Eigene Zusammenstellung"
18 | }
19 | }]
20 | }
21 |
--------------------------------------------------------------------------------
/data/linien_bhvbus.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_bhvbus",
3 | "headline": "Bus Bremerhaven",
4 | "access": [{
5 | "x_source": "BHV",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_BHV"
10 | ],
11 | "data": [{
12 | "id": "linien_bhvbus",
13 | "short": "Linie",
14 | "long": "Laufweg",
15 | "file": "sources/linien_bhvbus.csv",
16 | "source": {
17 | "name": "Eigene Zusammenstellung"
18 | },
19 | "license": {
20 | "name": "CC-BY-SA 4.0",
21 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
22 | "owner": {
23 | "type": "twitter",
24 | "name": "FloEllebrecht"
25 | }
26 | },
27 | "comments": [
28 | "Stand 2020"
29 | ]
30 | }]
31 | }
32 |
--------------------------------------------------------------------------------
/data/linien_bsag.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_bsag",
3 | "headline": "Straßenbahnlinien Bremen",
4 | "access": [{
5 | "x_source": "HB",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_HB"
10 | ],
11 | "data": [{
12 | "id": "linien_bsag",
13 | "short": "Linie",
14 | "long": "Laufweg",
15 | "file": "sources/linien_bsag.csv",
16 | "source": {
17 | "name": "Eigene Zusammenstellung"
18 | },
19 | "license": {
20 | "name": "CC-BY-SA 4.0",
21 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
22 | "owner": {
23 | "type": "twitter",
24 | "name": "FloEllebrecht"
25 | }
26 | },
27 | "comments": [
28 | "Stand 2020",
29 | "Beinhaltet alle aktuellen Linien",
30 | "Beinhaltet diverse E-Linien (Schülerverkehr, vereinfachte Einsetzer/Aussetzer)",
31 | "Sofern die Nummer aktuell nicht vergeben ist, sind ehemalige Linien vorhanden"
32 | ]
33 | }]
34 | }
35 |
--------------------------------------------------------------------------------
/data/linien_by.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_by",
3 | "headline": "ÖPNV Bayern",
4 | "access": [{
5 | "x_source": "BY",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_BY"
10 | ],
11 | "data": [{
12 | "id": "linien_by",
13 | "short": "Linie",
14 | "long": "Laufweg",
15 | "file": "sources/linien_by.csv",
16 | "source": {
17 | "name": "Eigene Zusammenstellung"
18 | },
19 | "license": {
20 | "name": "CC0",
21 | "url": "https://creativecommons.org/share-your-work/public-domain/cc0",
22 | "owner": {
23 | "type": "twitter",
24 | "name": "SimonBredemeier"
25 | },
26 | "contributors": [{
27 | "type": "twitter",
28 | "name": "der_heubi"
29 | }]
30 | }
31 | }]
32 | }
33 |
--------------------------------------------------------------------------------
/data/linien_dd.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_dd",
3 | "headline": "Linien Dresden",
4 | "access": [{
5 | "x_source": "DD",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_DD"
10 | ],
11 | "data": [{
12 | "id": "linien_dd",
13 | "short": "Linie",
14 | "long": "Laufweg",
15 | "delim": ",",
16 | "alias": "|",
17 | "file": "sources/linien_dd.csv",
18 | "source": {
19 | "name": "Eigene Zusammenstellung"
20 | },
21 | "license": {
22 | "name": "CC-BY-SA 4.0",
23 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
24 | "owner": {
25 | "type": "twitter",
26 | "name": "moritzkraehe"
27 | },
28 | "contributors": [{
29 | "type": "twitter",
30 | "name": "jonaes_"
31 | }]
32 | }
33 | }]
34 | }
35 |
--------------------------------------------------------------------------------
/data/linien_de_fv.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_de_fv",
3 | "headline": "Fernverkehrslinien Deutschland",
4 | "access": [{
5 | "x_source": "DS",
6 | "type": "/"
7 | }, {
8 | "x_source": "DE",
9 | "type": "/"
10 | }],
11 | "magic_hashtags": [
12 | "DS100",
13 | "_DE",
14 | "🇩🇪"
15 | ],
16 | "data": [{
17 | "id": "linien_de_fv",
18 | "short": "Linie",
19 | "long": "Laufweg",
20 | "file": "sources/linien_de_fv.csv",
21 | "source": {
22 | "name": "Eigene Zusammenstellung"
23 | },
24 | "license": {
25 | "name": "CC0",
26 | "url": "https://creativecommons.org/share-your-work/public-domain/cc0",
27 | "owner": {
28 | "type": "twitter",
29 | "name": "SimonBredemeier"
30 | }
31 | }
32 | }]
33 | }
34 |
--------------------------------------------------------------------------------
/data/linien_delbus.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_delbus",
3 | "headline": "Bus Delmenhorst",
4 | "access": [{
5 | "x_source": "DEL",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_DEL"
10 | ],
11 | "data": [{
12 | "id": "linien_delbus",
13 | "short": "Linie",
14 | "long": "Laufweg",
15 | "file": "sources/linien_delbus.csv",
16 | "source": {
17 | "name": "Eigene Zusammenstellung"
18 | },
19 | "license": {
20 | "name": "CC-BY-SA 4.0",
21 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
22 | "owner": {
23 | "type": "twitter",
24 | "name": "FloEllebrecht"
25 | }
26 | },
27 | "comments": [
28 | "Stand 2020"
29 | ]
30 | }]
31 | }
32 |
--------------------------------------------------------------------------------
/data/linien_ffm.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_ffm",
3 | "headline": "Linien Frankfurt",
4 | "description": "Kommunale Nahverkehrslinien in Frankfurt",
5 | "access": [{
6 | "x_source": "FFM",
7 | "type": "/"
8 | }],
9 | "magic_hashtags": [
10 | "_FFM",
11 | "🍎🚋",
12 | "🚋🍎",
13 | "🚋🍏 ",
14 | "🍏🚋"
15 | ],
16 | "data": [{
17 | "id": "linien_ffm",
18 | "short": "Nummer",
19 | "long": "Laufweg",
20 | "delim": ",",
21 | "alias": ";",
22 | "file": "sources/linien_ffm.csv",
23 | "source": {
24 | "name": "Eigene Zusammenstellung"
25 | },
26 | "license": {
27 | "name": "Standardlizenz",
28 | "contributors": [{
29 | "type": "twitter",
30 | "name": "MoritzKraehe"
31 | }],
32 | "contributors": [{
33 | "type": "twitter",
34 | "name": "jonaes_"
35 | }]
36 | }
37 | }]
38 | }
39 |
--------------------------------------------------------------------------------
/data/linien_hg.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_hg",
3 | "headline": "Linien Hochtaunuskreis",
4 | "description": "Buslinien im Hochtaunuskreis",
5 | "access": [{
6 | "x_source": "HG",
7 | "type": "/"
8 | }],
9 | "magic_hashtags": [
10 | "_HG"
11 | ],
12 | "data": [{
13 | "id": "linien_hg",
14 | "short": "Linie",
15 | "long": "Laufweg",
16 | "delim": ",",
17 | "alias": ";",
18 | "file": "sources/linien_hg.csv",
19 | "source": {
20 | "name": "Eigene Zusammenstellung"
21 | },
22 | "license": {
23 | "name": "CC0",
24 | "url": "https://creativecommons.org/share-your-work/public-domain/cc0",
25 | "owner": {
26 | "type": "twitter",
27 | "name": "jonaes_"
28 | }
29 | }
30 | }]
31 | }
32 |
--------------------------------------------------------------------------------
/data/linien_koeln.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_koeln",
3 | "headline": "Linien Köln",
4 | "description": "Straßenbahnlinien im VRS in Köln",
5 | "access": [{
6 | "x_source": "KÖ",
7 | "type": "/"
8 | }, {
9 | "x_source": "KOE",
10 | "type": "/"
11 | }],
12 | "magic_hashtags": [
13 | "_KÖLN",
14 | "_KOELN"
15 | ],
16 | "data": [{
17 | "short": "Linie",
18 | "long": "Laufweg",
19 | "file": "sources/linien_koeln.csv",
20 | "source": {
21 | "name": "Eigene Zusammenstellung"
22 | },
23 | "license": {
24 | "name": "CC-BY-SA 3.0",
25 | "url": "https://creativecommons.org/licenses/by-sa/3.0/",
26 | "owner": {
27 | "type": "twitter",
28 | "name": "koelschlenny"
29 | }
30 | }
31 | }]
32 | }
33 |
--------------------------------------------------------------------------------
/data/linien_mv.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_mv",
3 | "headline": "SPNV-Linien Mecklenburg-Vorpommern",
4 | "access": [{
5 | "x_source": "MV",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_MV"
10 | ],
11 | "data": [{
12 | "id": "linien_mv",
13 | "short": "Linie",
14 | "long": "Name/Laufweg/Betreiber",
15 | "delim": ";",
16 | "file": "sources/linien_mv.csv",
17 | "source": {
18 | "name": "Eigene Zusammenstellung"
19 | },
20 | "license": {
21 | "name": "CC-BY-SA 4.0",
22 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
23 | "owner": {
24 | "type": "twitter",
25 | "name": "jonasr_97"
26 | }
27 | }
28 | }]
29 | }
30 |
--------------------------------------------------------------------------------
/data/linien_ni.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_ni",
3 | "headline": "Regionalbahnlinien Niedersachsen",
4 | "access": [{
5 | "x_source": "NI",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_NI"
10 | ],
11 | "data": [{
12 | "id": "linien_ni",
13 | "short": "Linie",
14 | "long": "Laufweg",
15 | "delim": ";",
16 | "file": "sources/linien_ni.csv",
17 | "source": {
18 | "name": "Eigene Zusammenstellung"
19 | },
20 | "license": {
21 | "name": "CC0",
22 | "url": "https://creativecommons.org/share-your-work/public-domain/cc0",
23 | "owner": {
24 | "type": "twitter",
25 | "name": "SimonBredemeier"
26 | }
27 | }
28 | }]
29 | }
30 |
--------------------------------------------------------------------------------
/data/linien_nl.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_nl",
3 | "headline": "SPV Niederlande",
4 | "access": [{
5 | "x_source": "NL",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_NL",
10 | "🇳🇱"
11 | ],
12 | "data": [{
13 | "id": "linien_nl",
14 | "short": "Linie",
15 | "long": "Laufweg",
16 | "file": "sources/linien_nl.csv",
17 | "source": {
18 | "name": "Eigene Zusammenstellung"
19 | },
20 | "license": {
21 | "name": "CC0",
22 | "url": "https://creativecommons.org/share-your-work/public-domain/cc0",
23 | "owner": {
24 | "type": "twitter",
25 | "name": "SimonBredemeier"
26 | }
27 | }
28 | }]
29 | }
30 |
--------------------------------------------------------------------------------
/data/linien_no.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_no",
3 | "headline": "SPV Norwegen",
4 | "access": [{
5 | "x_source": "NO",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_NO",
10 | "🇳🇴"
11 | ],
12 | "data": [{
13 | "id": "linien_no",
14 | "short": "Linje",
15 | "long": "Vei",
16 | "file": "sources/linien_no.csv",
17 | "source": {
18 | "name": "Liniennummernschema von 2023"
19 | },
20 | "comments": [
21 | "Stand: 2023"
22 | ]
23 | }]
24 | }
25 |
--------------------------------------------------------------------------------
/data/linien_nvs.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_nvs",
3 | "headline": "ÖPNV-Linien in Schwerin",
4 | "description": "ÖPNV-Linien im Stadtgebiet Potsdam außer Bahn-Verkehr",
5 | "access": [{
6 | "x_source": "SCHWERIN",
7 | "type": "/"
8 | }],
9 | "magic_hashtags": [
10 | "_SCHWERIN"
11 | ],
12 | "data": [{
13 | "id": "linien_nvs",
14 | "short": "Linie",
15 | "long": "Laufweg",
16 | "file": "sources/linien_nvs.csv",
17 | "source": {
18 | "name": "Straßenbahn- und Buslinien der Nahverkehr Schwerin GmbH; Eigene Zusammenstellung auf Basis der Webseite"
19 | },
20 | "license": {
21 | "name": "CC-BY-SA 4.0",
22 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
23 | "owner": {
24 | "type": "twitter",
25 | "name": "jonasr_97"
26 | }
27 | }
28 | }, {
29 | "id": "linien_vlp",
30 | "short": "Linie",
31 | "long": "Laufweg",
32 | "file": "sources/linien_vlp.csv",
33 | "source": {
34 | "name": "Buslinien der Verkehrsgesellschaft Ludwigslust-Parchim mbH; Eigene Zusammenstellung auf Basis der Webseite"
35 | },
36 | "license": {
37 | "name": "CC-BY-SA 4.0",
38 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
39 | "owner": {
40 | "type": "twitter",
41 | "name": "jonasr_97"
42 | }
43 | }
44 | }, {
45 | "id": "linien_nwm",
46 | "short": "Linie",
47 | "long": "Laufweg",
48 | "file": "sources/linien_nwm.csv",
49 | "source": {
50 | "name": "Buslinien der NAHBUS Nordwestmecklenburg GmbH; Eigene Zusammenstellung auf Basis der Webseite"
51 | },
52 | "license": {
53 | "name": "CC-BY-SA 4.0",
54 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
55 | "owner": {
56 | "type": "twitter",
57 | "name": "jonasr_97"
58 | }
59 | }
60 | }]
61 | }
62 |
--------------------------------------------------------------------------------
/data/linien_nw.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_nw",
3 | "headline": "Regionalbahnlinien Nordrhein-Westfalen",
4 | "access": [{
5 | "x_source": "NW",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_NW"
10 | ],
11 | "data": [{
12 | "id": "linien_nw",
13 | "short": "Linie",
14 | "long": "Laufweg",
15 | "delim": ";",
16 | "file": "sources/linien_nw.csv",
17 | "source": {
18 | "name": "Eigene Zusammenstellung auf Basis des NRW Fahrplanbuch 2022",
19 | "url": "https://www.mobil.nrw/fileadmin/01_Content_Sales_Hub/Downloadcenter/NRW_Fahrplanbuch_2022.pdf"
20 | },
21 | "license": {
22 | "name": "CC0",
23 | "url": "https://creativecommons.org/share-your-work/public-domain/cc0",
24 | "owner": {
25 | "type": "twitter",
26 | "name": "C1710"
27 | }
28 | },
29 | "comments": [
30 | "Stand: Januar 2022"
31 | ]
32 | }]
33 | }
34 |
--------------------------------------------------------------------------------
/data/linien_opr.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_opr",
3 | "headline": "Buslinien im Landkreis Ostprignitz-Ruppin ",
4 | "description": "Buslinien, die von der Ostprignitz-Ruppiner Personennahverkehrsgesellschaft mbH betrieben werden",
5 | "access": [{
6 | "x_source": "OPR",
7 | "type": "/"
8 | }],
9 | "magic_hashtags": [
10 | "_OPR"
11 | ],
12 | "data": [{
13 | "id": "linien_opr",
14 | "short": "Linie",
15 | "long": "Laufweg",
16 | "file": "sources/linien_opr.csv",
17 | "source": {
18 | "name": "Eigene Zusammenstellung auf Basis von orp-busse.de",
19 | "url": "https://www.orp-busse.de"
20 | },
21 | "license": {
22 | "name": "CC-BY-SA 4.0",
23 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
24 | "owner": {
25 | "type": "twitter",
26 | "name": "jonasr_97"
27 | }
28 | }
29 | }]
30 | }
31 |
--------------------------------------------------------------------------------
/data/linien_p.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_p",
3 | "headline": "ÖPNV-Linien in Potsdam",
4 | "description": "ÖPNV-Linien im Stadtgebiet Potsdam außer Bahn-Verkehr",
5 | "access": [{
6 | "x_source": "P",
7 | "type": "/"
8 | }],
9 | "magic_hashtags": [
10 | "_P"
11 | ],
12 | "data": [{
13 | "id": "linien_p",
14 | "short": "Linie",
15 | "long": "Laufweg",
16 | "file": "sources/linien_p.csv",
17 | "source": {
18 | "name": "Eigene Zusammenstellung auf Basis von: Liniennetz Potsdam & Websites der Verkehrsunternehmen ViP, regiobus, VTF, HVG, BVG"
19 | },
20 | "license": {
21 | "name": "CC-BY-SA 4.0",
22 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
23 | "owner": {
24 | "type": "twitter",
25 | "name": "jonasr_97"
26 | }
27 | }
28 | }]
29 | }
30 |
--------------------------------------------------------------------------------
/data/linien_rmv.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_rmv",
3 | "headline": "SPNV Rhein-Main-Verkehrsverbund",
4 | "access": [{
5 | "x_source": "RMV",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_RMV"
10 | ],
11 | "data": [{
12 | "id": "linien_rmv",
13 | "short": "Liniennummer",
14 | "long": "Name, Laufweg, Betreiber",
15 | "file": "sources/linien_rmv.csv",
16 | "comments": [
17 | "Die Liniennamen stammen aus dem Kursbuch des RMV"
18 | ],
19 | "source": {
20 | "name": "Eigene Zusammenstellung"
21 | },
22 | "license": {
23 | "name": "CC0",
24 | "url": "https://creativecommons.org/share-your-work/public-domain/cc0",
25 | "owner": {
26 | "type": "twitter",
27 | "name": "jonaes_"
28 | }
29 | }
30 | }]
31 | }
32 |
--------------------------------------------------------------------------------
/data/linien_rnv.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_rnv",
3 | "headline": "Straßenbahnlinien des RNV",
4 | "access": [{
5 | "x_source": "RNV",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_RNV"
10 | ],
11 | "data": [{
12 | "id": "linien_rnv",
13 | "short": "Nummer",
14 | "long": "Laufweg",
15 | "file": "sources/linien_rnv.csv",
16 | "source": {
17 | "name": "Eigene Zusammenstellung"
18 | },
19 | "license": {
20 | "name": "CC-BY-SA 4.0",
21 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
22 | "owner": {
23 | "type": "twitter",
24 | "name": "moritzkraehe"
25 | }
26 | }
27 | }]
28 | }
29 |
--------------------------------------------------------------------------------
/data/linien_rvf.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_rvf",
3 | "headline": "Straßenbahnlinien Freiburg",
4 | "access": [{
5 | "x_source": "RVF",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_RVF"
10 | ],
11 | "data": [{
12 | "id": "linien_rvf",
13 | "short": "Linie",
14 | "long": "Laufweg",
15 | "file": "sources/linien_rvf.csv",
16 | "source": {
17 | "name": "Eigene Zusammenstellung"
18 | },
19 | "license": {
20 | "name": "CC-BY-SA 4.0",
21 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
22 | "owner": {
23 | "type": "twitter",
24 | "name": "FloEllebrecht"
25 | },
26 | "contributors": [{
27 | "type": "twitter",
28 | "name": "trassenfinder"
29 | }]
30 | },
31 | "comments": [
32 | "Stand 2020",
33 | "Enthält alle Linien des RVF",
34 | "Nachtlinien fangen mit N an",
35 | "Bürgerbus Breisach fangen mit BB an",
36 | "Linien aus Emmendingen fangen mit EN an",
37 | "Außerdem: NB für Neuenburg, SB für Stadtbus Breisach"
38 | ]
39 | }]
40 | }
41 |
--------------------------------------------------------------------------------
/data/linien_sh.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_sh",
3 | "headline": "Regionalbahnlinien Schleswig-Holstein",
4 | "access": [{
5 | "x_source": "SH",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_SH"
10 | ],
11 | "data": [{
12 | "id": "linien_sh",
13 | "short": "Linie",
14 | "long": "Laufweg",
15 | "delim": ";",
16 | "file": "sources/linien_sh.csv",
17 | "source": {
18 | "name": "Eigene Zusammenstellung"
19 | },
20 | "license": {
21 | "name": "CC0",
22 | "url": "https://creativecommons.org/share-your-work/public-domain/cc0",
23 | "owner": {
24 | "type": "twitter",
25 | "name": "SimonBredemeier"
26 | }
27 | }
28 | }]
29 | }
30 |
--------------------------------------------------------------------------------
/data/linien_sn.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_sn",
3 | "headline": "Linien Sachsen",
4 | "access": [{
5 | "x_source": "SN",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_SN"
10 | ],
11 | "data": [{
12 | "id": "linien_sn",
13 | "short": "Linie",
14 | "long": "Laufweg",
15 | "delim": ",",
16 | "alias": "|",
17 | "file": "sources/linien_sn.csv",
18 | "source": {
19 | "name": "Eigene Zusammenstellung"
20 | },
21 | "license": {
22 | "name": "CC-BY-SA 4.0",
23 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
24 | "owner": {
25 | "type": "twitter",
26 | "name": "moritzkraehe"
27 | }
28 | }
29 | }]
30 | }
31 |
--------------------------------------------------------------------------------
/data/linien_th.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_th",
3 | "headline": "SPNV Thüringen",
4 | "access": [{
5 | "x_source": "TH",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_TH"
10 | ],
11 | "data": [{
12 | "id": "linien_th",
13 | "short": "Linie",
14 | "long": "Laufweg und Betreiber",
15 | "file": "sources/linien_th.csv",
16 | "source": {
17 | "name": "Eigene Zusammenstellung"
18 | },
19 | "license": {
20 | "name": "CC0",
21 | "url": "https://creativecommons.org/share-your-work/public-domain/cc0",
22 | "owner": {
23 | "type": "twitter",
24 | "name": "jonaes_"
25 | },
26 | "contributors": [{
27 | "type": "twitter",
28 | "name": "SimonBredemeier"
29 | }]
30 | }
31 | }]
32 | }
33 |
--------------------------------------------------------------------------------
/data/linien_vab.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_vab",
3 | "headline": "Buslinien Aschaffenburg",
4 | "access": [{
5 | "x_source": "VAB",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_VAB"
10 | ],
11 | "data": [{
12 | "id": "linien_vab_sa",
13 | "short": "Linie",
14 | "long": "Laufweg",
15 | "file": "sources/linien_vab_stadt_ab.csv",
16 | "source": {
17 | "name": "Eigene Zusammenstellung"
18 | },
19 | "license": {
20 | "name": "CC0",
21 | "url": "https://creativecommons.org/share-your-work/public-domain/cc0",
22 | "owner": {
23 | "type": "twitter",
24 | "name": "BlubbBlubber3"
25 | }
26 | },
27 | "comments": [
28 | "Buslinien der Stadt Aschaffenburg"
29 | ]
30 | },{
31 | "id": "linien_vab_ka",
32 | "short": "Linie",
33 | "long": "Laufweg",
34 | "file": "sources/linien_vab_kreis_ab.csv",
35 | "source": {
36 | "name": "Eigene Zusammenstellung"
37 | },
38 | "license": {
39 | "name": "CC0",
40 | "url": "https://creativecommons.org/share-your-work/public-domain/cc0",
41 | "owner": {
42 | "type": "twitter",
43 | "name": "BlubbBlubber3"
44 | }
45 | },
46 | "comments": [
47 | "Buslinien des Kreises Aschaffenburg"
48 | ]
49 | },{
50 | "id": "linien_vab_km",
51 | "short": "Linie",
52 | "long": "Laufweg",
53 | "file": "sources/linien_vab_kreis_mb.csv",
54 | "source": {
55 | "name": "Eigene Zusammenstellung"
56 | },
57 | "license": {
58 | "name": "CC0",
59 | "url": "https://creativecommons.org/share-your-work/public-domain/cc0",
60 | "owner": {
61 | "type": "twitter",
62 | "name": "BlubbBlubber3"
63 | }
64 | },
65 | "comments": [
66 | "Buslinien des Kreises Miltenberg"
67 | ]
68 | }]
69 | }
70 |
--------------------------------------------------------------------------------
/data/linien_vbb.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_vbb",
3 | "headline": "SPNV-Linien Berlin/Brandenburg",
4 | "access": [{
5 | "x_source": "VBB",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_VBB",
10 | "🧸"
11 | ],
12 | "data": [{
13 | "id": "linien_vbb",
14 | "short": "Linie",
15 | "long": "Bezeichnung/Laufweg/Betreiber",
16 | "delim": ";",
17 | "file": "sources/linien_vbb.csv",
18 | "source": {
19 | "name": "Eigene Zusammenstellung"
20 | },
21 | "license": {
22 | "name": "CC-BY-SA 4.0",
23 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
24 | "owner": {
25 | "type": "twitter",
26 | "name": "jonasr_97"
27 | },
28 | "contributors": [{
29 | "type": "twitter",
30 | "name": "jonaes_"
31 | }]
32 | }
33 | }]
34 | }
35 |
--------------------------------------------------------------------------------
/data/linien_vvs.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_vvs",
3 | "headline": "ÖPNV-Linien Stuttgart",
4 | "access": [{
5 | "x_source": "STG",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_STG"
10 | ],
11 | "data": [{
12 | "id": "linien_vvs",
13 | "short": "Linie",
14 | "long": "Streckenverlauf",
15 | "file": "sources/linien_vvs.csv",
16 | "alias": ",",
17 | "source": {
18 | "name": "VVS Open Data Portal",
19 | "url": "https://www.openvvs.de/dataset/linien"
20 | },
21 | "license": {
22 | "name": "CC-BY 4.0",
23 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
24 | "owner": {
25 | "type": "link",
26 | "name": "Verkehrs- und Tarifverbund Stuttgart",
27 | "url": "https://vvs.de"
28 | }
29 | },
30 | "comments": [
31 | "Stand 2019"
32 | ]
33 | }]
34 | }
35 |
--------------------------------------------------------------------------------
/data/linien_wtv.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "linien_wtv",
3 | "headline": "Bus Waldshuter TV",
4 | "access": [{
5 | "x_source": "WTV",
6 | "type": "/"
7 | }],
8 | "magic_hashtags": [
9 | "_WTV"
10 | ],
11 | "data": [{
12 | "id": "linien_wtv",
13 | "short": "Linie",
14 | "long": "Laufweg",
15 | "file": "sources/linien_wtv.csv",
16 | "source": {
17 | "name": "Eigene Zusammenstellung"
18 | },
19 | "license": {
20 | "name": "CC-BY-SA 4.0",
21 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
22 | "owner": {
23 | "type": "twitter",
24 | "name": "FloEllebrecht"
25 | }
26 | },
27 | "comments": [
28 | "Stand 2020"
29 | ]
30 | }]
31 | }
32 |
--------------------------------------------------------------------------------
/data/orte_at.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_at",
3 | "headline": "Betriebsstellen in Österreich",
4 | "access": [{
5 | "x_source": "AT",
6 | "type": "#"
7 | },{
8 | "x_source": "ÖBB",
9 | "type": "#"
10 | }],
11 | "magic_hashtags": [
12 | "_AT",
13 | "DB640",
14 | "ÖBB",
15 | "🇦🇹"
16 | ],
17 | "data": [{
18 | "id": "orte_at",
19 | "short": "Abk",
20 | "long": "Name",
21 | "delim": ";",
22 | "nolink": true,
23 | "file": "sources/orte_at_db640.csv",
24 | "source": {
25 | "name": "Betriebsstellen Österreich laut DB 640",
26 | "modified": true
27 | },
28 | "comments": [
29 | "Quelle ist nicht offiziell.",
30 | "Groß-/Kleinschreibung muss beachtet werden, es sind auch Kleinbuchstaben erlaubt!"
31 | ]
32 | }]
33 | }
34 |
--------------------------------------------------------------------------------
/data/orte_be.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_be",
3 | "description": "Telegraph Codes for Belgian railway stations^",
4 | "headline": "Betriebsstellen Belgien",
5 | "access": [{
6 | "x_source": "BE",
7 | "type": "#"
8 | }],
9 | "magic_hashtags": [
10 | "_BE",
11 | "🇧🇪"
12 | ],
13 | "data": [{
14 | "id": "orte_de",
15 | "short": "telegraph-code",
16 | "long": "name",
17 | "delim": ",",
18 | "nolink": true,
19 | "file": "sources/orte_be.csv",
20 | "description": "Telegraph Codes",
21 | "source": {
22 | "name": "Open transport data in Belgium",
23 | "url": "https://github.com/iRail/stations/pull/166/commits",
24 | "modified": false
25 | },
26 | "license": {
27 | "name": "CC-0",
28 | "url": "https://creativecommons.org/publicdomain/zero/1.0/"
29 | }
30 | }]
31 | }
32 |
--------------------------------------------------------------------------------
/data/orte_ca.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_ca",
3 | "headline": "Betriebsstellen Kanada",
4 | "access": [{
5 | "x_source": "CA",
6 | "type": "#"
7 | }],
8 | "magic_hashtags": [
9 | "_CA",
10 | "🇨🇦"
11 | ],
12 | "data": [{
13 | "id": "orte_ca_via",
14 | "short": "Station Code",
15 | "long": "Station Name",
16 | "delim": ";",
17 | "nolink": true,
18 | "file": "sources/orte_ca_via.csv",
19 | "description": "Bahnhofskürzel der VIA Rail Canada",
20 | "source": {
21 | "name": "Eigene Zusammenstellung aus OSM-Daten"
22 | }
23 | }]
24 | }
25 |
--------------------------------------------------------------------------------
/data/orte_ch.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_ch",
3 | "headline": "Betriebsstellen in der Schweiz",
4 | "access": [{
5 | "x_source": "CH",
6 | "type": "#"
7 | }],
8 | "magic_hashtags": [
9 | "_CH",
10 | "🇨🇭"
11 | ],
12 | "data": [{
13 | "id": "orte_ch",
14 | "short": "Abkuerzung",
15 | "long": "BEZEICHNUNG_OFFIZIELL",
16 | "delim": ";",
17 | "file": "sources/orte_ch_didok.csv",
18 | "source": {
19 | "name": "Haltestellen des öffentlichen Verkehrs",
20 | "url": "https://opendata.swiss/de/dataset/haltestellen-des-offentlichen-verkehrs",
21 | "modified": true
22 | },
23 | "license": {
24 | "name": "ähnlich CC-BY",
25 | "url": "https://opendata.swiss/de/dataset?q=haltestelle&organization=bundesamt-fur-verkehr-bav&res_rights=NonCommercialAllowed-CommercialAllowed-ReferenceRequired",
26 | "owner": {
27 | "type": "name",
28 | "name": "SBB"
29 | }
30 | },
31 | "comments": [
32 | "Aus der der Originalquelle sind nur diejenigen Einträge übernommen, die wirklich eine Abkürzung haben."
33 | ]
34 | }, {
35 | "id": "orte_ch_add",
36 | "short": "Abk",
37 | "long": "Name",
38 | "file": "sources/orte_ch_add.csv",
39 | "source": {
40 | "name": "Eigene Zusammenstellung"
41 | },
42 | "license": {
43 | "name": "Standardlizenz",
44 | "contributors": [{
45 | "type": "twitter",
46 | "name": "Stechny"
47 | },{
48 | "type": "twitter",
49 | "name": "TWeinlein"
50 | },{
51 | "type": "twitter",
52 | "name": "danihaenni"
53 | }]
54 | },
55 | "comments": [
56 | "Zusätzliche Kürzel aus privaten Informationen"
57 | ]
58 | }]
59 | }
60 |
--------------------------------------------------------------------------------
/data/orte_dd.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_dd",
3 | "headline": "Haltestellen Dresden",
4 | "access": [{
5 | "x_source": "DD",
6 | "type": "#"
7 | }],
8 | "magic_hashtags": [
9 | "_DD"
10 | ],
11 | "data": [{
12 | "id": "orte_dd",
13 | "short": "Abkürzung",
14 | "long": "Haltestelle",
15 | "delim": ";",
16 | "nolink": true,
17 | "file": "sources/orte_dd.csv",
18 | "description": "Haltestellen Dresden",
19 | "source": {
20 | "name": "Haltestellenkürzel der Dresdener Verkehrsbetriebe AG",
21 | "url": "https://www.dvb.de/de-de/fahrplan/haltestellenauskunft/haltestellenkuerzel/"
22 | }
23 | }]
24 | }
25 |
--------------------------------------------------------------------------------
/data/orte_de.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_de",
3 | "description": "Eisenbahnbetriebsstellen, Bahnhöfe und Haltepunkte in Deutschland",
4 | "headline": "Betriebsstellen Deutschland",
5 | "access": [{
6 | "x_source": "DS",
7 | "type": "#"
8 | }, {
9 | "x_source": "DE",
10 | "type": "#"
11 | }],
12 | "magic_hashtags": [
13 | "DS100",
14 | "_DE",
15 | "🇩🇪"
16 | ],
17 | "data": [{
18 | "id": "ds100",
19 | "short": "RL100-Code",
20 | "long": "RL100-Langname",
21 | "delim": ";",
22 | "nolink": true,
23 | "file": "sources/orte_de_ds100.csv",
24 | "description": "Betriebsstellen der Deutschen Bahn nach Ril100",
25 | "source": {
26 | "name": "Betriebsstellenverzeichnis der Deutschen Bahn AG",
27 | "url": "https://data.deutschebahn.com/dataset/data-betriebsstellen",
28 | "modified": true
29 | },
30 | "license": {
31 | "name": "CC-BY 4.0",
32 | "url": "https://creativecommons.org/licenses/by/4.0/",
33 | "owner": {
34 | "type": "name",
35 | "name": "Deutsche Bahn AG"
36 | }
37 | },
38 | "comments": [
39 | "Stand 07/2021"
40 | ]
41 | }, {
42 | "id": "orte_de_add",
43 | "short": "Abk",
44 | "long": "Name",
45 | "file": "sources/orte_de_add.csv",
46 | "source": {
47 | "name": "Eigene Zusammenstellung"
48 | },
49 | "comments": [
50 | "Zusätzliche Kürzel aus privaten Informationen"
51 | ]
52 | }]
53 | }
54 |
--------------------------------------------------------------------------------
/data/orte_dk.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_dk",
3 | "headline": "Betriebsstellen Dänemark",
4 | "access": [{
5 | "x_source": "DK",
6 | "type": "#"
7 | }],
8 | "magic_hashtags": [
9 | "_DK",
10 | "🇩🇰"
11 | ],
12 | "data": [{
13 | "id": "orte_dk",
14 | "short": "FORKORTELSE",
15 | "long": "NAVN",
16 | "delim": ";",
17 | "nolink": true,
18 | "file": "sources/orte_dk.csv",
19 | "description": "Betriebsstellen Dänemark",
20 | "source": {
21 | "name": "Strækningsregister",
22 | "url": "https://www.bane.dk/da/Leverandoer/Krav/Tekniske-data",
23 | "modified": true
24 |
25 | },
26 | "filter": [{
27 | "col": "FILTER",
28 | "contains": "STED",
29 | "empty": true
30 | }],
31 | "comments": [
32 | "Aus der Gesamtliste sind die Einträge gefiltert, die keinen Bindestrich enthalten (Formel =WENNFEHLER(FINDEN(\"-\",G2,1);\"STED\"))",
33 | "Für Grenaa Havn wird aus technischen Gründen #DK:Gr_H statt '#DK:Gr.H' verwendet."
34 | ]
35 | }]
36 | }
37 |
--------------------------------------------------------------------------------
/data/orte_ffm.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_ffm",
3 | "headline": "Haltestellen Frankfurt",
4 | "access": [{
5 | "x_source": "FFM",
6 | "type": "#"
7 | }],
8 | "magic_hashtags": [
9 | "_FFM",
10 | "🍎🚋",
11 | "🚋🍎",
12 | "🚋🍏 ",
13 | "🍏🚋"
14 | ],
15 | "data": [{
16 | "id": "orte_ffm",
17 | "short": "Abk",
18 | "long": "Name",
19 | "delim": ";",
20 | "file": "sources/orte_ffm.csv",
21 | "source": {
22 | "name": "Eigene Zusammenstellung, Hilfe aus privaten Nachrichten und dem Frankfurter Nahverkehrsforum",
23 | "url": "https://frankfurter-nahverkehrsforum.de/forum/index.php?thread/20682-stationskürzel/",
24 | "modified": true
25 | },
26 | "comments": [
27 | "Alle Stadtbahn- und von der Leitstelle betreuten Straßenbahnhaltestellen haben ein Kürzel aus zwei Buchstaben",
28 | "Bei Kreuzungsbahnhöfen im Stadtbahnbereich hat jede Ebene einen dritten Buchstaben",
29 | "Andere Betriebsstellen haben längere Kürzel.",
30 | "Alle Stadtbahnhaltestellen haben dreistellige Nummern",
31 | "Straßenbahnhaltestellen haben vierstellige Nummern (diese sind allerdings nur lückenhaft bekannt)",
32 | "Die Kürzel für Wendeanlagen fangen mit einem Unterstrich an '_'. Dies kann mit Magic Hashtags kollidieren (und tut es mindestens bei _HB), daher sollten diese nur voll qualifiziert benutzt werden, also als '#FFM:_HB'."
33 | ]
34 | }]
35 | }
36 |
--------------------------------------------------------------------------------
/data/orte_fr.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_fr",
3 | "headline": "Betriebsstellen in Frankreich",
4 | "access": [{
5 | "x_source": "FR",
6 | "type": "#"
7 | }],
8 | "magic_hashtags": [
9 | "_FR",
10 | "🇫🇷"
11 | ],
12 | "data": [{
13 | "id": "orte_fr",
14 | "short": "Abréviation",
15 | "long": "Définition",
16 | "delim": ";",
17 | "file": "sources/orte_sncf.csv",
18 | "source": {
19 | "name": "Lexique des abréviations SNCF",
20 | "url": "https://ressources.data.sncf.com/explore/dataset/lexique-des-acronymes-sncf/",
21 | "modified": true
22 | },
23 | "license": {
24 | "name": "ODbL",
25 | "url": "https://opendatacommons.org/licenses/odbl/",
26 | "owner": {
27 | "type": "name",
28 | "name": "SNCF"
29 | }
30 | },
31 | "comments": [
32 | "Scheinbar war die Originalquelle früher all-caps und wird langsam umgestellt. Das ist aber nur bis C oder D gekommen, danach wird's etwas uneinheitlich."
33 | ]
34 | }]
35 | }
36 |
--------------------------------------------------------------------------------
/data/orte_hh.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_hamburg",
3 | "headline": "Haltestellen Hochbahn Hamburg",
4 | "access": [{
5 | "x_source": "HH",
6 | "type": "#"
7 | }],
8 | "magic_hashtags": [
9 | "_HH",
10 | "🍔"
11 | ],
12 | "data": [{
13 | "id": "orte_hh",
14 | "short": "Abk",
15 | "long": "Name",
16 | "delim": ";",
17 | "file": "sources/orte_hamburg.csv",
18 | "source": {
19 | "name": "Hamburger-Bahnhöfe.de",
20 | "url": "http://hamburger-bahnhoefe.de/"
21 | },
22 | "comments": [
23 | "Privat zusammengestellte Liste"
24 | ]
25 | }]
26 | }
27 |
--------------------------------------------------------------------------------
/data/orte_ibnr.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_ibnr",
3 | "headline": "Bahnhofsnummern Deutschland",
4 | "access": [{
5 | "x_source": "IBNR",
6 | "type": "#"
7 | }],
8 | "magic_hashtags": [
9 | "IBNR",
10 | "🚉"
11 | ],
12 | "data": [{
13 | "id": "orte_de_stationsdaten",
14 | "short": "Bf. Nr.",
15 | "long": "Station",
16 | "file": "sources/orte_de_stationsdaten.csv",
17 | "source": {
18 | "name": "Stationsdaten",
19 | "url": "https://data.deutschebahn.com/dataset/data-stationsdaten"
20 | },
21 | "license": {
22 | "name": "CC-BY 4.0",
23 | "url": "https://creativecommons.org/licenses/by/4.0/",
24 | "owner": {
25 | "type": "name",
26 | "name": "Deutsche Bahn AG"
27 | }
28 | },
29 | "comments": [
30 | "Stand 03/2020",
31 | "Stationsnummern"
32 | ]
33 | }]
34 | }
35 |
--------------------------------------------------------------------------------
/data/orte_leitpunkte.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_leitpunkte",
3 | "headline": "Leitpunkte Deutschland",
4 | "description": "Wegepunkte auf Fahrkartencodes",
5 | "access": [{
6 | "x_source": "LP",
7 | "type": "#"
8 | }],
9 | "magic_hashtags": [
10 | "_LP"
11 | ],
12 | "data": [{
13 | "id": "leitpunkte",
14 | "short": "Abk",
15 | "long": "Name",
16 | "delim": ";",
17 | "file": "sources/orte_leitpunkte.csv",
18 | "source": {
19 | "name": "Tarifpunkte in den Beförderungsbedingungen der DB",
20 | "url": "https://www.bahn.de/p/view/mdb/bahnintern/agb/entfernungswerk/mdb_305971_teil_2-3_tarifpunkte_anstobahnhfe_regionen.pdf",
21 | "modified": false
22 | },
23 | "license": {
24 | "name": " ",
25 | "owner": {
26 | "type": "name",
27 | "name": "Deutsche Bahn AG"
28 | }
29 | }
30 | }]
31 | }
32 |
--------------------------------------------------------------------------------
/data/orte_nl.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_nl",
3 | "headline": "Betriebsstellen Niederlande",
4 | "access": [{
5 | "x_source": "NL",
6 | "type": "#"
7 | }],
8 | "magic_hashtags": [
9 | "_NL",
10 | "🇳🇱"
11 | ],
12 | "data": [{
13 | "id": "orte_nl",
14 | "short": "Abk",
15 | "long": "Name",
16 | "delim": ";",
17 | "file": "sources/orte_nl.csv",
18 | "source": {
19 | "name": "Anhang 6 zu Regeling spoorverkeer",
20 | "url": "https://wetten.overheid.nl/BWBR0017707/2020-04-01/#Bijlage6"
21 | },
22 | "license": {
23 | "name": "Gemeinfrei, da Gesetz"
24 | },
25 | "comments": [
26 | "Stand 2020"
27 | ]
28 | }]
29 | }
30 |
--------------------------------------------------------------------------------
/data/orte_no.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_no",
3 | "description": "Eisenbahnbetriebsstellen Norwegen",
4 | "headline": "Betriebsstellen Norwegen",
5 | "access": [{
6 | "x_source": "NO",
7 | "type": "#"
8 | }],
9 | "magic_hashtags": [
10 | "_NO",
11 | "🇳🇴"
12 | ],
13 | "data": [{
14 | "id": "orte_no",
15 | "short": "Fork",
16 | "long": "Navn",
17 | "delim": ";",
18 | "nolink": true,
19 | "file": "sources/orte_no.csv",
20 | "description": "Betriebsstellen Norwegen",
21 | "source": {
22 | "name": "Grafische Fahrpläne, Stand 2020",
23 | "url": "https://www.banenor.no/kundeportal/ruter-og-sportilgang/grafiske-togruter1/",
24 | "modified": true
25 | },
26 | "comments": [
27 | "Selbst abgetippt"
28 | ]
29 | }]
30 | }
31 |
--------------------------------------------------------------------------------
/data/orte_nvs.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_nvs",
3 | "headline": "Haltestellen vom Nahverkehr Schwerin",
4 | "access": [{
5 | "x_source": "SCHWERIN",
6 | "type": "#"
7 | }],
8 | "magic_hashtags": [
9 | "_SCHWERIN"
10 | ],
11 | "data": [{
12 | "id": "orte_nvs",
13 | "short": "Abkürzung",
14 | "long": "Haltestelle",
15 | "file": "sources/orte_nvs.csv",
16 | "source": {
17 | "name": "Eigene Zusammenstellung auf Basis von: Website Nahverkehr Schwerin (NVS)"
18 | },
19 | "license": {
20 | "name": "CC-BY-SA 4.0",
21 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
22 | "owner": {
23 | "type": "twitter",
24 | "name": "jonasr_97"
25 | }
26 | }
27 | }]
28 | }
29 |
--------------------------------------------------------------------------------
/data/orte_se.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_se",
3 | "headline": "Betriebsstellen Schweden",
4 | "access": [{
5 | "x_source": "SE",
6 | "type": "#"
7 | }],
8 | "magic_hashtags": [
9 | "_SE",
10 | "🇸🇪"
11 | ],
12 | "data": [{
13 | "id": "orte_se",
14 | "short": "Abk",
15 | "long": "Name",
16 | "file": "sources/orte_se.csv",
17 | "source": {
18 | "name": "Svensk Wikipedia",
19 | "url": "https://sv.wikipedia.org/wiki/Lista_över_trafikplatssignaturer_i_det_svenska_järnvägsnätet"
20 | },
21 | "license": {
22 | "name": "CC-BY-SA 4.0",
23 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
24 | "owner": {
25 | "type": "twitter",
26 | "name": "FloEllebrecht"
27 | }
28 | }
29 | }]
30 | }
31 |
--------------------------------------------------------------------------------
/data/orte_uk.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_uk",
3 | "headline": "Betriebsstellen Großbritannien",
4 | "access": [{
5 | "x_source": "UK",
6 | "type": "#"
7 | },{
8 | "x_source": "GB",
9 | "type": "#"
10 | }],
11 | "magic_hashtags": [
12 | "_UK",
13 | "_GB",
14 | "🇬🇧"
15 | ],
16 | "data": [{
17 | "id": "orte_uk_crs",
18 | "short": "CRS Code",
19 | "long": "Station Name",
20 | "delim": ",",
21 | "file": "sources/orte_uk_crs.csv",
22 | "source": {
23 | "name": "National Rail Enquiries",
24 | "url": "https://www.nationalrail.co.uk/stations_destinations/48541.aspx",
25 | "modified": true
26 | },
27 | "comments": [
28 | "Dreistellige Kürzel",
29 | "Stand 2018"
30 | ]
31 | },{
32 | "id": "orte_uk_long",
33 | "short": "Abbr",
34 | "long": "Name",
35 | "delim": ";",
36 | "file": "sources/orte_uk_long.csv",
37 | "source": {
38 | "name": "Rail Delivery Group",
39 | "url": "http://data.atoc.org/how-to",
40 | "modified": true
41 | },
42 | "license": {
43 | "name": "CC-BY 4.0",
44 | "url": "https://creativecommons.org/licenses/by/4.0/",
45 | "owner": {
46 | "type": "name",
47 | "name": "Rail Delivery Group"
48 | }
49 | },
50 | "comments": [
51 | "Detaillierte Betriebsstellen",
52 | "Aus Fixed-width-Text extrahiert",
53 | "Namen mit Kleinbuchstaben versehen",
54 | "4- bis 7-stellige Kürzel",
55 | "Stand 2020"
56 | ]
57 | }]
58 | }
59 |
--------------------------------------------------------------------------------
/data/orte_wien.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "orte_wien",
3 | "headline": "Haltestellen Wien",
4 | "access": [{
5 | "x_source": "W",
6 | "type": "#"
7 | }],
8 | "magic_hashtags": [
9 | "_W"
10 | ],
11 | "data": [{
12 | "id": "orte_wien",
13 | "short": "Abk",
14 | "long": "Name",
15 | "delim": ";",
16 | "file": "sources/orte_wien.csv",
17 | "source": {
18 | "name": "Christoph Schönweilers hauptsignal.at",
19 | "url": "https://bahn.hauptsignal.at/"
20 | },
21 | "comments": [
22 | "Datenbanksuche auf hauptsignal.at",
23 | "Stand 2020"
24 | ]
25 | }]
26 | }
27 |
--------------------------------------------------------------------------------
/data/regeln_de.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "regeln_de",
3 | "headline": "Eisenbahnbegriffe (Deutschland)",
4 | "description": "Abkürzungen aus Betriebsregelwerk des VDV und Ril 408 der Deutschen Bahn",
5 | "access": [{
6 | "x_source": "DS",
7 | "type": "&"
8 | }],
9 | "magic_hashtags": [
10 | "DS100",
11 | "_DE",
12 | "DS301",
13 | "_SH",
14 | "_NI",
15 | "_RMV",
16 | "DV301",
17 | "_TH",
18 | "🇩🇪"
19 | ],
20 | "data": [{
21 | "id": "ril408",
22 | "short": "Abk",
23 | "long": "Name",
24 | "alias": ",",
25 | "nolink": true,
26 | "file": "sources/regeln_de.csv",
27 | "source": {
28 | "name": "Eigene Zusammenstellung"
29 | },
30 | "license": {
31 | "name": "CC-BY-SA 4.0",
32 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
33 | "owner": {
34 | "type": "twitter",
35 | "name": "autinerd"
36 | }
37 | },
38 | "comments": [
39 | "Liste ist auf Bahn-eigene und nicht komplett offensichtliche Abkürzungen („Ellok“ für „Elektrolokomotive“) begrenzt",
40 | "Groß- und Kleinschreibung ist sehr wichtig. Beispiele: „ZS“: Zugsammelschiene, „Zs“: Zugschaffner.",
41 | "Signaltypen gibt es doppelt: „Asig“ und „ASig“ bzw. „Zvsig“ und „ZVsig“."
42 | ]
43 | }]
44 | }
45 |
--------------------------------------------------------------------------------
/data/regeln_vkms.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "regeln_vkm",
3 | "headline": "Fahrzeughalterkennzeichen",
4 | "description": "Alle in der EU registrierten Fahrzeughalter",
5 | "access": [{
6 | "x_source": "VKM",
7 | "type": "&"
8 | }],
9 | "magic_hashtags": [
10 | "_EVU",
11 | "_VKM",
12 | "🇪🇺"
13 | ],
14 | "data": [{
15 | "id": "vkm_liste",
16 | "short": "UNIQUE",
17 | "long": "Keeper Name / Halter Name / Nom du détenteur / Название владельца",
18 | "nolink": true,
19 | "file": "sources/regeln_vkms.csv",
20 | "source": {
21 | "name": "Vehicle Keeper Marking register (VKM)",
22 | "url": "https://www.era.europa.eu/system/files/2023-02/IU-VKM-publiclist-155.xls"
23 | },
24 | "license": {
25 | "name": "ähnlich CC-BY",
26 | "url": "https://www.era.europa.eu/content/disclaimer-and-copyright-notice",
27 | "owner": {
28 | "type": "name",
29 | "name": "European Union Agency for Railways"
30 | }
31 | }
32 | }]
33 | }
34 |
--------------------------------------------------------------------------------
/data/signale_bostrab.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "signale_bostrab",
3 | "headline": "Straßenbahnsignale",
4 | "description": "BOStrab",
5 | "access": [{
6 | "x_source": "BO",
7 | "type": "%"
8 | }, {
9 | "x_source": "BOSTRAB",
10 | "type": "%"
11 | }],
12 | "magic_hashtags": [
13 | "BOSTRAB",
14 | "_FFM",
15 | "_HH",
16 | "_HB",
17 | "_STG",
18 | "_KOELN",
19 | "_KÖLN",
20 | "_RNV",
21 | "_DD",
22 | "🍎🚋",
23 | "🚋🍎",
24 | "🚋🍏 ",
25 | "🍏🚋",
26 | "🍔"
27 | ],
28 | "data": [{
29 | "id": "bostrab",
30 | "short": "Abk",
31 | "long": "Bedeutung",
32 | "file": "sources/signale_bostrab.csv",
33 | "source": {
34 | "name": "Eigene Zusammenstellung"
35 | },
36 | "license": {
37 | "name": "CC-BY-SA 4.0",
38 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
39 | "owner": {
40 | "type": "twitter",
41 | "name": "moritzkraehe"
42 | }
43 | }
44 | }]
45 | }
46 |
--------------------------------------------------------------------------------
/data/signale_de_ds301.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "signale_de_ds301",
3 | "headline": "Eisenbahnsignale Westdeutschland",
4 | "description": "DS301 der Deutschen Bahn",
5 | "access": [{
6 | "x_source": "DS",
7 | "type": "%"
8 | }],
9 | "magic_hashtags": [
10 | "DS301",
11 | "DS100",
12 | "_DE",
13 | "_SH",
14 | "_NI",
15 | "_RMV",
16 | "🇩🇪"
17 | ],
18 | "data": [{
19 | "id": "ds301",
20 | "short": "DSAbk",
21 | "long": "Beschreibung",
22 | "add": "Kurzname",
23 | "delim": ";",
24 | "alias": "|",
25 | "file": "sources/signale_de.csv",
26 | "filter": [{
27 | "col": "DS/DV",
28 | "contains": "DS",
29 | "empty": true
30 | }],
31 | "source": {
32 | "name": "Eigene Zusammenstellung"
33 | },
34 | "license": {
35 | "name": "CC-BY-SA 4.0",
36 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
37 | "owner": {
38 | "type": "twitter",
39 | "name": "autinerd"
40 | },
41 | "contributors": [{
42 | "type": "twitter",
43 | "name": "baeuchle"
44 | }]
45 | }
46 | }]
47 | }
48 |
--------------------------------------------------------------------------------
/data/signale_de_dv301.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "signale_de_dv301",
3 | "headline": "Eisenbahnsignale Ostdeutschland",
4 | "description": "DV301 der Deutschen Bahn",
5 | "access": [{
6 | "x_source": "DV",
7 | "type": "%"
8 | }],
9 | "magic_hashtags": [
10 | "DV301",
11 | "_TH"
12 | ],
13 | "data": [{
14 | "id": "dv301",
15 | "short": "DVAbk",
16 | "long": "Beschreibung",
17 | "add": "Kurzname",
18 | "delim": ";",
19 | "alias": "|",
20 | "file": "sources/signale_de.csv",
21 | "filter": [{
22 | "col": "DS/DV",
23 | "contains": "DV",
24 | "empty": true
25 | }],
26 | "source": {
27 | "name": "Eigene Zusammenstellung"
28 | },
29 | "license": {
30 | "name": "CC-BY-SA 4.0",
31 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
32 | "owner": {
33 | "type": "twitter",
34 | "name": "autinerd"
35 | }
36 | },
37 | "comments": [
38 | "Signalnamen mit \"/\" können aus technischen Gründen nicht beantwortet werden. Das betrifft Vr1/2."
39 | ]
40 | }]
41 | }
42 |
--------------------------------------------------------------------------------
/data/signale_de_gemein.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "signale_de_gemein",
3 | "headline": "Eisenbahnsignale Gemeines Signalbuch",
4 | "description": "Erfundene Signalbegriffe zum Lachen",
5 | "access": [{
6 | "x_source": "GSB",
7 | "type": "%"
8 | }, {
9 | "x_source": "GEMEIN",
10 | "type": "%"
11 | }],
12 | "magic_hashtags": [
13 | "_GSB"
14 | ],
15 | "data": [{
16 | "id": "gemein",
17 | "short": "Abk",
18 | "long": "Kurzname",
19 | "add": "Bedeutung",
20 | "delim": ";",
21 | "file": "sources/signale_de_gemein.csv",
22 | "source": {
23 | "name": "Eigene Zusammenstellung"
24 | },
25 | "license": {
26 | "name": "CC0",
27 | "url": "https://creativecommons.org/share-your-work/public-domain/cc0",
28 | "owner": {
29 | "type": "twitter",
30 | "name": "9Lukas5"
31 | }
32 | },
33 | "comments": [
34 | "Original-Autor des gemeinen Signalbuches unbekannt"
35 | ]
36 | }]
37 | }
38 |
--------------------------------------------------------------------------------
/data/signale_no.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "signale_no",
3 | "headline": "Norske signale",
4 | "access": [{
5 | "x_source": "NO",
6 | "type": "%"
7 | }],
8 | "magic_hashtags": [
9 | "_NO",
10 | "🇳🇴"
11 | ],
12 | "data": [{
13 | "id": "signale_no",
14 | "short": "Nummer",
15 | "long": "Betydning",
16 | "alias": ",",
17 | "file": "sources/signale_no.csv",
18 | "source": {
19 | "name": "Trykk 401"
20 | }
21 | }]
22 | }
23 |
--------------------------------------------------------------------------------
/data/strecken_ch.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "strecken_ch",
3 | "headline": "Strecken Schweiz",
4 | "access": [{
5 | "x_source": "CH",
6 | "type": "$"
7 | }],
8 | "magic_hashtags": [
9 | "_CH",
10 | "🇨🇭"
11 | ],
12 | "data": [{
13 | "id": "strecken_ch_sbb",
14 | "short": "linie",
15 | "long": "linienname",
16 | "file": "sources/strecken_ch_sbb.csv",
17 | "source": {
18 | "name": "Liniennetz der SBB",
19 | "url": "https://opendata.swiss/de/dataset/linie"
20 | },
21 | "license": {
22 | "name": "ähnlich CC-BY",
23 | "url": "https://opendata.swiss/de/terms-of-use/#terms_by",
24 | "owner": {
25 | "type": "name",
26 | "name": "SBB"
27 | }
28 | }
29 | }]
30 | }
31 |
--------------------------------------------------------------------------------
/data/strecken_de.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "strecken_de",
3 | "description": "Eisenbahnstrecken Deutschland",
4 | "access": [{
5 | "x_source": "DS",
6 | "type": "$"
7 | }, {
8 | "x_source": "DE",
9 | "type": "$"
10 | }],
11 | "magic_hashtags": [
12 | "DS100",
13 | "_DE",
14 | "🇩🇪"
15 | ],
16 | "data": [{
17 | "id": "vzg",
18 | "short": "STRNR",
19 | "long": "STRKURZN",
20 | "add": "STRNAME",
21 | "delim": ";",
22 | "nolink": true,
23 | "file": "sources/strecken_de_vzg.csv",
24 | "description": "Streckennummern nach VzG / Stredax",
25 | "source": {
26 | "name": "Geo-Streckennetz",
27 | "url": "https://data.deutschebahn.com/dataset/geo-strecke",
28 | "modified": true
29 | },
30 | "license": {
31 | "name": "CC-BY 4.0",
32 | "url": "https://creativecommons.org/licenses/by/4.0/",
33 | "owner": {
34 | "type": "name",
35 | "name": "Deutsche Bahn AG"
36 | }
37 | }
38 | },{
39 | "id": "kbs",
40 | "short": "Tabellennummer",
41 | "long": "Laufweg",
42 | "add": "Liniennummer",
43 | "alias": ",",
44 | "nolink": true,
45 | "file": "sources/strecken_de_kbs.csv",
46 | "description": "Kursbuchstrecken",
47 | "source": {
48 | "name": "Kursbuch der Deutschen Bahn",
49 | "url": "http://kursbuch.bahn.de/hafas/kbview.exe/dn?rt=1&dosearch=1&searchmode=tableplus&table_nr= &controlpattern=P.ddd&mainframe=utable&tocinfo=reg_tab"
50 | },
51 | "license": {
52 | "name": " ",
53 | "owner": {
54 | "type": "name",
55 | "name": "Deutsche Bahn AG"
56 | }
57 | },
58 | "comments": [
59 | "Dreistellige Streckennummern",
60 | "Unternummern sind auf die erste Zahl reduziert, z.B. $645.3 für die KBS 645.3-4"
61 | ]
62 | },{
63 | "id": "kbs_alt",
64 | "short": "Tabellennummer",
65 | "long": "Laufweg",
66 | "add": "Liniennummer",
67 | "alias": ",",
68 | "nolink": true,
69 | "file": "sources/strecken_de_alt.csv",
70 | "description": "ehemalige Kursbuchstrecken",
71 | "source": {
72 | "name": "Eigene Zusammenstellung"
73 | },
74 | "license": {
75 | "name": "CC-BY-SA 4.0",
76 | "url": "https://creativecommons.org/licenses/by-sa/4.0/",
77 | "owner": {
78 | "type": "twitter",
79 | "name": "jonasr_97"
80 | }
81 | }
82 | },{
83 | "id": "strecken_de_namen",
84 | "short": "Abk",
85 | "long": "Beschreibung",
86 | "add": "Nummer",
87 | "alias": ",",
88 | "nolink": true,
89 | "file": "sources/strecken_de_namen.csv",
90 | "description": "Zusätzliche Streckennamen aus eigener Zusammenstellung",
91 | "source": {
92 | "name": "Eigene Zusammenstellung"
93 | }
94 | }]
95 | }
96 |
--------------------------------------------------------------------------------
/data/strecken_ffm.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "strecken_ffm",
3 | "headline": "Stadtbahnstrecken Frankfurt",
4 | "access": [{
5 | "x_source": "FFM",
6 | "type": "$"
7 | }],
8 | "magic_hashtags": [
9 | "_FFM",
10 | "🍎🚋",
11 | "🚋🍎",
12 | "🚋🍏 ",
13 | "🍏🚋"
14 | ],
15 | "data": [{
16 | "id": "strecken_ffm",
17 | "short": "Abk",
18 | "long": "Weg",
19 | "alias": ",",
20 | "file": "sources/strecken_ffm.csv",
21 | "source": {
22 | "name": "Eigene Zusammenstellung aus Krakies/Nagel",
23 | "url": "https://de.wikipedia.org/wiki/Vorlage:Krakies/Nagel",
24 | "modified": true
25 | },
26 | "comments": [
27 | "Alle Bauabschnitte der Stadtbahnstrecken können mit großen lateinischen Buchstaben oder den Unicode-Zeichen für römische Zahlen geschrieben werden: ‚$FFM:DIV‘ = ‚$FFM:DⅣ‘ = ‚$FFM:Dⅳ‘."
28 | ]
29 | }]
30 | }
31 |
--------------------------------------------------------------------------------
/data/strecken_no.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "strecken_no",
3 | "headline": "Strecken Norwegen",
4 | "access": [{
5 | "x_source": "NO",
6 | "type": "$"
7 | }],
8 | "magic_hashtags": [
9 | "_NO",
10 | "🇳🇴"
11 | ],
12 | "data": [{
13 | "id": "strecken_no",
14 | "short": "Blad",
15 | "long": "Vei",
16 | "file": "sources/strecken_no.csv",
17 | "source": {
18 | "name": "Grafische Fahrpläne, Stand 2020",
19 | "url": "https://www.banenor.no/kundeportal/ruter-og-sportilgang/grafiske-togruter1/",
20 | "modified": true
21 | },
22 | "comments": [
23 | "Selbst abgetippt"
24 | ]
25 | }]
26 | }
27 |
--------------------------------------------------------------------------------
/doc/aufbau-antworten.md:
--------------------------------------------------------------------------------
1 |
2 |
DS-100: Aufbau der Antworten
3 | Wie sind die Antworten des Bots strukturiert und was bedeutet alles?
4 |
5 |
6 | Aufbau der Antworten des Bots
7 | =============================
8 |
9 | Findet der Bot in einem Status erweiterbare Abkürzungen, so antwortet er
10 | auf diesen Status mit diesen Erweiterungen. Hierbei wird eine Zeile pro
11 | Abkürzung geschrieben:
12 |
13 | FF: Frankfurt (Main) Hbf
14 | 1733: Hannover --Kassel-- - Würzburg
15 |
16 | Ist die Quelle für die Abkürzung nicht DS100 oder BOT, so wird die
17 | Quelle vorangestellt:
18 |
19 | FFM#HB: Frankfurt Hauptbahnhof
20 | FFM$A3: Anschlussstrecke A3: Abzweig Nordwest - Oberursel Hohemark
21 |
22 | Mehrere Kürzel werden in der Reihenfolge beantwortet, in der sie
23 | auftauchen; mehrfach wiederholte gleiche Kürzel werden nur beim ersten
24 | Mal beantwortet.
25 |
26 | Ist die Antwort zu lange für einen Status, antwortet der Bot mit dem
27 | nächsten Teil seiner Antwort auf den vorherigen Teil, sodass ein
28 | Thread seiner Antworten entsteht.
29 |
--------------------------------------------------------------------------------
/doc/avatar-bahn.social.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 | @ril100@bahn.social
10 |
11 |
14 |
15 | ]]>
16 | https://avatar.frankfurtium.de/ril100@bahn.social.svg
17 | https://avatar.frankfurtium.de/ds100.svg
18 | https://avatar.frankfurtium.de/ds100.svg
19 | © Bjørn Bäuchle CC-0 4.0
20 | image/svg+xml
21 | Image
22 | @ril100@bahn.social
23 | 2022-11-08
24 |
25 |
26 |
27 |
38 |
39 |
40 |
41 | bahn.
42 | social
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/doc/avatar-ril100.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 | DS100
10 |
11 |
14 |
15 | ]]>
16 | https://avatar.frankfurtium.de/ril100.svg
17 | https://avatar.frankfurtium.de/ril100.svg
18 | © Bjørn Bäuchle CC-0 4.0
19 | image/svg+xml
20 | Image
21 | Ril100
22 | 2022-03-31
23 |
24 |
25 |
26 |
37 |
38 |
39 |
40 | Ril 100
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/doc/avatar-zug.network.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 | @ril100@zug.network
10 |
11 |
14 |
15 | ]]>
16 | https://avatar.frankfurtium.de/ril100@zug.network.svg
17 | https://avatar.frankfurtium.de/ds100.svg
18 | https://avatar.frankfurtium.de/ds100.svg
19 | © Bjørn Bäuchle CC-0 4.0
20 | image/svg+xml
21 | Image
22 | @ril100@zug.network
23 | 2022-11-08
24 |
25 |
26 |
27 |
38 |
39 |
40 |
41 | zug.
42 | network
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/doc/avatar.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 | DS100
10 |
11 |
14 |
15 | ]]>
16 | https://avatar.frankfurtium.de/ds100.svg
17 | https://avatar.frankfurtium.de/ds100.svg
18 | © Bjørn Bäuchle CC-0 4.0
19 | image/svg+xml
20 | Image
21 | DS100
22 | 2019-06-20
23 |
24 |
25 |
26 |
37 |
38 |
39 |
40 | DS 100
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/doc/bot.css:
--------------------------------------------------------------------------------
1 | h1::before {
2 | content: "";
3 | display: inline-block;
4 | background-image: url(https://avatar.frankfurtium.de/ds100.svg);
5 | background-size: 100% 100%;
6 | height: 25px;
7 | width: 25px;
8 | }
9 |
10 | blockquote {
11 | border: thin blue solid;
12 | font-family: sans-serif;
13 | padding: .5em;
14 | border-radius: 1em;
15 | }
16 |
17 | blockquote.antwort {
18 | margin-left: 6em;
19 | }
20 |
21 | blockquote.antwort2 {
22 | margin-left: 9em;
23 | }
24 |
25 | blockquote.antwort3 {
26 | margin-left: 12em;
27 | }
28 |
29 | blockquote::before {
30 | display: block;
31 | margin-bottom: .5em;
32 | color: #888;
33 | }
34 |
35 | table, th, td {
36 | border-collapse: collapse;
37 | border: thin black solid;
38 | }
39 |
40 | table tbody th {
41 | text-align: left;
42 | }
43 |
44 | table tbody td {
45 | text-align: center;
46 | }
47 |
48 | table.dumptable tbody td {
49 | text-align: left;
50 | }
51 |
52 | table.dumptable tbody th {
53 | text-align: left;
54 | font-family: monospace;
55 | }
56 |
57 | th.yes, td.yes {
58 | background-color: #00ff00;
59 | }
60 |
61 | th.note, td.note {
62 | background-color: #ffd000;
63 | }
64 |
65 | th.no, td.no {
66 | background-color: #ff8080;
67 | }
68 |
69 | header, main, section {
70 | clear: both;
71 | }
72 |
73 | navi p {
74 | display: block;
75 | float: left;
76 | margin-right: 1em;
77 | margin-top: .1em;
78 | margin-bottom: .3em;
79 | }
80 |
81 | navi p:before {
82 | content: "☰ ";
83 | display: inline-block;
84 | margin-right: .2em;
85 | }
86 |
87 | .closenavi:before {
88 | content: "× ";
89 | display: inline-block;
90 | font-size: 200%;
91 | font-weight: bold;
92 | }
93 |
94 | div.shownnavi {
95 | width: 250px;
96 | }
97 |
98 | div.dumpnavi.shownnavi {
99 | max-width: 100%;
100 | min-width: 400px;
101 | }
102 |
103 | div.hiddennavi {
104 | width: 0px;
105 | }
106 |
107 | div.sidenavi {
108 | height: 100%;
109 | position: fixed;
110 | z-index: 1;
111 | top: 0;
112 | left: 0;
113 | transition: 0.5s;
114 | overflow-x: hidden;
115 | background-color: #c0d0ff;
116 | }
117 |
118 | div.dumpnavi {
119 | height: 100%;
120 | position: fixed;
121 | z-index: 1;
122 | top: 0;
123 | right: 0;
124 | transition: 1s;
125 | overflow-x: hidden;
126 | overflow-y: scroll;
127 | background-color: #c0d0ff;
128 | }
129 |
130 | navi ul {
131 | list-style-type: none;
132 | margin-left: 0;
133 | padding: 0;
134 | }
135 |
136 | navi ul li.hiddennavi div:before {
137 | content: "▷ ";
138 | }
139 |
140 | navi ul li.shownnavi div:before {
141 | content: "▽ ";
142 | }
143 |
144 | navi ul li {
145 | display: block;
146 | padding: .2em;
147 | background-color: #c0d0ff;
148 | color: #202840;
149 | }
150 |
151 | navi ul li:hover {
152 | background-color: #80a0ff;
153 | color: white;
154 | }
155 |
156 | navi ul li ul {
157 | transition: 0.5s;
158 | margin-left: 1em;
159 | }
160 |
161 | navi li a {
162 | display: block;
163 | color: white;
164 | text-decoration: none;
165 | color: inherit;
166 | width: 100%;
167 | }
168 |
169 | navi li > a {
170 | color: black;
171 | }
172 |
173 | navi li:hover > a {
174 | color: white;
175 | }
176 |
177 | navi ul li.transform_version:hover {
178 | background-color: #c0d0ff;
179 | color: black;
180 | }
181 |
182 | navi ul li.hiddennavi ul {
183 | display: none;
184 | }
185 |
186 | navi ul li.shownnavi ul {
187 | display: block;
188 | }
189 |
190 | div span.sigil {
191 | padding-right: .5em;
192 | font-weight: bold;
193 | font-family: monospace;
194 | }
195 |
196 | div.bigdumplist div.closenavi {
197 | display: none;
198 | }
199 |
200 | .only-mastodon {
201 | display: initial;
202 | color: #ff0000;
203 | }
204 |
205 | .only-mastodon:before {
206 | content: "";
207 | display: inline-block;
208 | background-image: url('mastodon-icon.png');
209 | background-size: 100% 100%;
210 | height: 16px;
211 | width: 16px;
212 | margin-right: 4px;
213 | }
214 |
--------------------------------------------------------------------------------
/doc/contribute.md:
--------------------------------------------------------------------------------
1 |
2 |
DS-100: Möglichkeiten, beizutragen
3 | Wie kann man beitragen, um den Bot zu verbessern oder ihm neues beizubringen?
4 |
5 |
6 | Beitragen
7 | =========
8 |
9 | Kommentare zum Bot, Fehlermeldungen und Ideen können gerne per Mastodon an
10 | den [Bot selbst](https://zug.network/@ril100) oder (besser) an
11 | [@baeuchle@chaos.social](https://chaos.social/@baeuchle) geschickt
12 | werden oder als Issue bei
13 | [github](https://github.com/baeuchle/ds100bot/) angelegt werden.
14 |
15 | Der Bot [beinhaltet](/copyright.html) Bahnabkürzungslisten von anderen
16 | Bahnverwaltungen und kann sehr gerne um noch andere Listen erweitert
17 | werden. Wer eine solche Liste hat und weitergeben darf, kann sich gerne
18 | melden, siehe vorheriger Absatz.
19 |
20 | Neue Daten sollten nach Möglichkeit mit [Datenliste im
21 | CSV-Format](/sources.html) kommen, sowie nach Möglichkeit mit einer
22 | [Konfigurationsdatei im JSON-Format](/data.html) (Details jeweils hinter
23 | dem Link.)
24 |
25 | Bedingungen zum Beitragen
26 | -------------------------
27 |
28 | Beiträge zum Code stehen unter [der gleichen Lizenz](/copyright.html)
29 | wie der restliche Code; die Autorenschaft ist bei github in der Commit
30 | history ersichtlich.
31 |
32 | Datenlisten können unter davon abweichenden Lizenzen stehen. Wichtig
33 | ist: [Die Betreibenden des Bots](/copyright.html) erhalten
34 | mindestens das uneingeschränkte Recht, die Datenliste als Dump zu
35 | veröffentlichen, anzupassen und die Datenliste im git-Repository zu
36 | archivieren. Die Erstellerin der Datenliste hat das Recht, ohne Angabe
37 | von Gründen die weitere Veröffentlichung zu untersagen, aber nicht, dass
38 | die git-Historie verändert wird, um die Daten nachträglich zu löschen.
39 |
40 | Einem Löschen der Datenliste nach Anforderung durch ihre Erstellerin
41 | kann eine direkte Wiederveröffentlichung durch die Betreibenden des Bots
42 | folgen, sofern die ursprüngliche Lizenz dies erlaubt. (Also etwa bei den
43 | CC-Lizenzen).
44 |
45 | Einzelne Einträge in den Datenlisten dürfen unter keinen Umständen Texte
46 | enthalten, auf die jemand urheberrechtliche Ansprüche stellt oder
47 | stellen kann.
48 |
--------------------------------------------------------------------------------
/doc/copyright.md:
--------------------------------------------------------------------------------
1 |
2 |
DS-100: Verwendete Daten und Lizenzen
3 | Welche Daten verwendet der Bot und welche rechtlichen Bedingungen gelten dafür?
4 |
5 |
6 | Daten und Urheberrecht
7 | ======================
8 |
9 | Output des Bots
10 | ---------------
11 |
12 | Die Statusmeldungen, die vom Bot erzeugt werden, besitzen keine
13 | ausreichende Schöpfungstiefe, die die Anwendung eines Urheberrechtes
14 | rechtfertigen würden.
15 |
16 | Datensammlungen
17 | ---------------
18 |
19 | Die vom Bot verwendeten [Datentabellen](/dumps/) besitzen u.U. eine
20 | genügend hohe Schöpfungstiefe. Soweit nicht anders angegeben, stehen
21 | diese Datensammlungen unter © [Apache Software Lizenz
22 | 2.0](http://www.apache.org/licenses/LICENSE-2.0) [Bjørn
23 | Bäuchle](https://chaos.social/@baeuchle).
24 |
25 | Dokumentation
26 | -------------
27 |
28 | Die vorliegende Sammlung von Dokumentationsseiten unterliegen © [Apache
29 | Software Lizenz 2.0](http://www.apache.org/licenses/LICENSE-2.0) [Bjørn
30 | Bäuchle](https://chaos.social/@baeuchle).
31 |
32 | Verwendete Daten
33 | ----------------
34 |
35 | Der Bot greift auf verschiedene Datenquellen zurück. Die Auswahl der
36 | Datenquelle geschieht auf Grund des ersten Teils des Suchbegriffs, etwa
37 | bei ‚\#DS:FF‘ der Teil ‚__\#DS:__‘. Ist kein solcher Teil vorhanden
38 | (‚FF‘) oder besteht er nur aus ‚__\#__‘ oder ‚__$__‘ (‚\#FF‘), werden
39 | die Quellen aus dem aktuellen __[Magic Hashtag](finde-listen.html)__
40 | oder __\#BOT__ (nur bei ‚__\#__‘) benutzt.
41 |
42 | Folgende Datenquellen werden vom Bot benutzt; Informationen zu den
43 | jeweiligen Lizenzen und Quellen finden sich bei den Dumps:
44 |
--------------------------------------------------------------------------------
/doc/datenschutz.md:
--------------------------------------------------------------------------------
1 |
2 |
DS-100: Datenschutz
3 | Es werden keine personalisierten Daten erhoben.
4 |
5 |
6 | Datenschutz
7 | ===========
8 |
9 | Der Bot erhebt oder speichert keine personalisierten Daten. Die Antworten
10 | des Bots sind nur auf dem jeweiligen Sozialen Netzwerk abrufbar; für die
11 | Daten, die dieses Netzwerk erhebt, besteht von Seiten des Bots keine
12 | Verantwortung.
13 |
14 | Der Bot speichert die letzte Status-ID, die er gesehen hat, damit er
15 | nicht zweimal auf den gleichen Status antwortet, sowie jede Abkürzung,
16 | die er in einem Status zu erkennen glaubte. Diese werden zusammen mit
17 | dem Erkennungsdatum und der Information, ob die Abkürzung einem
18 | Langnamen zugeordnet werden konnte, gespeichert. Es wird dabei nicht
19 | gespeichert, welcher User den Ursprungsstatus verfasst oder anderweitig
20 | zur Aufmerksamkeit des Bots gebracht hat (etwa durch Boost). Aus dieser
21 | Liste kann in regelmäßigen oder unregelmäßigen Abständen eine
22 | Zusammenstellung der am häufigsten gesuchten Abkürzungen und der
23 | nicht-erkannten Abkürzungen erstellt werden. Durch Löschen der
24 | entsprechenden Toots bei Mastodon sind diese Daten auch über den Bot
25 | oder dessen gespeicherte Daten nicht mehr zugänglich. Statistiken
26 | werden davon nicht beeinflusst, und die Details der Löschung obliegt dem
27 | jeweiligen Sozialen Netzwerk.
28 |
29 | Die Statistik wird an jedem ersten eines Monats für den letzten Monat,
30 | an jedem 1. Januar für das letzte Jahr und immer am 9. Juni (dem
31 | Geburtstag des Bots) für die gesamte Lebensdauer des Bots
32 | veröffentlicht.
33 |
34 | Beim Besuch *dieser* Seite werden im Rahmen der gesetzlichen
35 | Vorschriften keine personalisierten Daten erhoben. Es werden keine Cookies
36 | gesetzt und kein Inhalt von externen Servern, die nicht unter der gleichen
37 | Kontrolle wie dieser Server liegen, geladen.
38 |
--------------------------------------------------------------------------------
/doc/faq.md:
--------------------------------------------------------------------------------
1 |
2 |
DS-100: FAQ
3 | Sammlung von häufig gestellten Fragen
4 |
5 |
6 | Häufig gestellte Fragen
7 | =======================
8 |
9 | (oder was ich dafür halte)
10 |
11 | Siehe auch die [FAQ-Abkürzungsliste des Bots](/dumps/faq.html).
12 |
13 | Mach doch mal ein einfaches Beispiel!
14 | -------------------------------------
15 |
16 | - So sieht der Bot einen Status, und wahrscheinlich auch Antworten
17 | darauf:
18 |
19 | > @ril100@zug.network \#FF
20 |
21 | Warum antwortet mir der Bot nicht, obwohl er mir folgt?
22 | -------------------------------------------------------
23 |
24 | - Mastodon braucht manchmal ein bisschen Zeit, um Toots an die richtige
25 | Stelle zu liefern. Das ist systemimmanent und kann nicht verbessert
26 | werden.
27 | - Vielleicht ist er grade kaputt, der Rechner, auf dem er läuft
28 | überlastet oder was anderes läuft schief.
29 |
30 | Warum antwortet der Bot mir, obwohl ich das nicht will?
31 | -------------------------------------------------------
32 |
33 | - Der Bot antwortet Benutzerinnen, denen er folgt, automatisch, aber er
34 | folgt nicht automatisch. Siehe unten.
35 | - Bei Status von nicht-gefolgten Benutzerinnen reagiert er auf
36 | Erwähnungen und seine [Magic Hashtags](/finde-listen.html) – aber nur
37 | dann, wenn auch eine erweiterbare Abkürzung im Toot steckt. Wenn das
38 | nicht erwünscht ist, ist der Bot nicht beleidigt, wenn er geblockt
39 | wird. Da der Bot keine personalisierten Daten speichert, kann man ihm
40 | nicht anders sagen, dass man von ihm ignoriert werden will. Wem es
41 | egal ist, ob der Bot antwortet oder nicht, aber selbst die Antworten
42 | des Bots einfach nicht sehen will, kann den Bot auf Stumm schalten.
43 | - Soll der Bot nur auf einzelne Toots nicht antworten (aber das muss
44 | man vorher wissen), kann dieser Toot mit #NOBOT markiert werden.
45 | - Der Bot antwortet auch, wenn jemand anders einen Toot beantwortet und
46 | in dieser Antwort den Bot markiert oder einen der Magic Hashtags
47 | benutzt. Das kann für die Verfasserin des originalen Toots verwirrend
48 | sein.
49 |
50 | Warum ist Groß-/Kleinschreibung so wichtig?
51 | -------------------------------------------
52 |
53 | Ein Grundprinzip bei der Entwicklung des Bots ist „Don’t Spam”. Dazu
54 | zählt, dass es möglichst wenige „Kollateralfunde“ geben sollte – Dinge,
55 | die gar nicht beantwortet werden sollten. Je genauer ein bestimmtes
56 | Kürzel angegeben werden muss, desto kleiner die Wahrscheinlichkeit, dass
57 | es gar nicht gemeint war.
58 |
--------------------------------------------------------------------------------
/doc/finde-toots.md:
--------------------------------------------------------------------------------
1 |
2 |
DS-100: Finden von Toots
3 | Welche Toots betrachtet der Bot, um sie zu beantworten?
4 |
5 |
6 | Finden von Toots
7 | ================
8 |
9 | Der Bot durchsucht Mastodon nach
10 |
11 | - Toots in seiner Timeline, also von Benutzenden, denen der Bot folgt
12 | (siehe [Interaktion](/interaktion.html)). Antworten auf nicht-Gefolgte
13 | werden meistens nicht gefunden.
14 | - Toots, die den Bot erwähnen:
15 | - Explizite Erwähnungen (d.h., @ril100@zug.network steht im
16 | sichtbaren Text)
17 | - Implizite Erwähnungen (z.B. Antworten auf den Bot oder auf Toots,
18 | die den Bot erwähnen)
19 | - [Magic Hashtags](/finde-listen.html) können **nicht** dafür benutzt
20 | werden, Toots zu finden.
21 |
22 | Der Bot schließt aus:
23 |
24 | - Pure Boosts
25 | - Seine eigenen Toots
26 |
27 | Wird in einem Toot **A** ein anderer Toot **B** beantwortet oder
28 | zitiert, so wird Toot **B** ebenfalls betrachtet. Die
29 | Ausschlusskriterien treffen auch hier zu.
30 |
31 | Sind die Toots gefunden, wird als nächstes analysiert, [welche
32 | Abkürzungslisten benutzt werden sollen](/finde-listen.html)
33 |
--------------------------------------------------------------------------------
/doc/haftung.md:
--------------------------------------------------------------------------------
1 |
2 |
DS-100: Haftung
3 | Es wird keinerlei Haftung übernommen.
4 |
5 |
6 | Haftungsausschluss
7 | ==================
8 |
9 | Die Daten, die dieser Bot liefert, sollten richtig und vollständig sein,
10 | aber dafür wird keine Garantie gegeben.
11 |
12 | Schäden, die dadurch entstehen, dass dieser Bot fehlerhafte oder
13 | unvollständige Informationen liefert, liegen einzig und alleine in der
14 | Verantwortung derjenigen Person, die diese Informationen
15 | weiterverwendet.
16 |
17 | Insbesondere behält sich der Autor vor, einzelne Einträge zu löschen,
18 | nicht-offizielle Einträge hinzuzufügen und / oder Einträge zu
19 | verfälschen, und all dies __ohne gesonderte Ankündigung__. Besondere
20 | Vorsicht sei geboten bei #FO, was eventuell irgendwann nicht mehr "Stadt
21 | mit schlechtesten Autofahrern der Republik Hbf" heißen könnte.
22 |
--------------------------------------------------------------------------------
/doc/ignorelist.md:
--------------------------------------------------------------------------------
1 |
2 |
DS-100: Ignorierliste
3 | Was ist die Ignorierliste des Bots und warum gibt es sie?
4 |
5 |
6 | Ignorierliste
7 | =============
8 |
9 | Einige valide DS100-Kürzel werden auf Sozialen Medien oder im allgemeinen
10 | Sprachgebrauch ebenfalls benutzt und werden daher vom Bot nicht
11 | standardmäßig übersetzt. Beispiele sind Eisenbahnbegriffe wie __\#LZB__,
12 | __\#SBB__, aber auch profane Dinge wie __\#WLAN__ oder __\#ARD__. Bei
13 | [den anderen Dumps](/dumps/) gibt es eine vollständige [Liste der
14 | aktuellen Ignorierliste](/dumps/blacklist.html).
15 |
16 | Die Einträge auf der Ignoriertlist werden nicht gefunden, wenn nicht die
17 | Quelle angegeben ist: __\#WLAN__ wird nicht beantwortet, __\#DS:WLAN__
18 | schon.
19 |
20 | Es gibt bisher keine strukturierte Art und Weise, wie neue Begriffe auf
21 | die Ignorierliste kommen können, und keine Regeln, nach denen neue
22 | Begriffe ausgewählt werden, außer das Gutdünken des Autors.
23 |
--------------------------------------------------------------------------------
/doc/impressum.md:
--------------------------------------------------------------------------------
1 |
2 |
DS-100: Impressum
3 | Wer steckt hinter dem Bot?
4 |
5 |
6 | Impressum
7 | =========
8 |
9 | Die meisten Toots des Bots werden automatisch nach den [dargestellten
10 | Regeln](/finde-lang.html) erzeugt. Erklärungen und Hilfestellungen
11 | können auch von
12 | [@baeuchle@chaos.social](https://chaos.social/@baeuchle/) gegeben werden
13 | und sollten einfach erkennbar sein.
14 |
15 | Angaben gemäß §5 TMG:
16 | ---------------------
17 |
18 | Verantwortlich für diesen Bot und diese Seite ist:
19 | Dr. Bjørn Bäuchle
20 | Am Garten 1
21 | 34121 Kassel
22 | ds100 minus bot at frankfurtium dot de
23 |
24 | Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV:
25 | ----------------------------------------------------
26 |
27 | Bjørn Bäuchle
28 |
--------------------------------------------------------------------------------
/doc/index.md:
--------------------------------------------------------------------------------
1 |
2 |
DS100-Bot Startseite
3 | Erklärungen und Dokumentation zum Eisenbahnabkürzungsbot für
4 | Social Media
5 |
6 |
7 | DS100/Ril100-Bot
8 | ================
9 |
10 | Diese Seite beschreibt den Eisenbahnabkürzungsbot für
11 | Mastodon (@ril100@zug.network und @ril100@bahn.social ).
14 |
15 | Zweck des Bots
16 | --------------
17 |
18 | Der Bot soll helfen, Betriebsstellen Deutschen Bahn nach Ril 100
19 | (Betriebsstellenverzeichnis, ehemals DS 100) abzukürzen und trotzdem
20 | sicherzustellen, dass auch Dritte den Inhalt des Toots verstehen
21 | können.
22 |
23 | Der Bot entspringt aus einem privaten Wochenendprojekt und wird _pro
24 | bono_ betrieben; es stehen keine wirtschaftlichen Interessen und keine
25 | Umsatz- oder Gewinnabsicht hinter Erstellung und / oder Betreiben des Bots.
26 |
27 | Twitter vs. Mastodon
28 | --------------------
29 |
30 | Dieser Bot wurde ursprünglich für Twitter geschrieben und später so erweitert,
31 | dass er auch bei Mastodon eingesetzt werden kann. Da aus Twitter
32 | mittlerweile ein faschistisches Arschlochloch geworden ist, wird dieses
33 | Netzwerk nicht mehr unterstützt.
34 |
35 | Instanz-spezifische Mastodon-Accounts
36 | =====================================
37 |
38 | Der Account @ril100@bahn.social beantwortet
40 | Toots in der lokalen Timeline der jeweiligen Bahn-zentrierten
41 | Mastodon-Instanzen.
42 |
43 | Kurze Funktionsübersicht: Vier Schritte
44 | ---------------------------------------
45 |
46 | Der Bot funktioniert in vier Schritten:
47 |
48 | 1. [Suche nach Toots](/finde-toots.html), die eventuell beantwortet
49 | werden könnten
50 | 2. [Herausfinden](/finde-listen.html), welche
51 | [Abkürzungslisten](/copyright.html) benutzt werden sollen
52 | 3. Suche nach [Abkürzungen](/finde-lang.html) in Spoilertext,
53 | Toot-Inhalt und Bild-Alternativtexten
54 | 4. [Antwort auf die Toots](/aufbau-antworten.html) erstellen, in dem die
55 | Abkürzungen ausgeschrieben werden.
56 |
57 | Mit dem Bot kann auch [interagiert](/interaktion.html) werden.
58 |
--------------------------------------------------------------------------------
/doc/interaktion.md:
--------------------------------------------------------------------------------
1 |
2 |
DS-100: Interaktion
3 | Wie kann man mit dem Bot interagieren?
4 |
5 |
6 | Interaktion mit dem Bot
7 | =======================
8 |
9 | Der Bot kann Benutzerinnen automatisch folgen, um ihre Toots in seiner
10 | Timeline zu sehen und damit ohne gesonderte Aufwände auf diese Toots zu
11 | antworten.
12 |
13 | Hierfür muss der Bot explizit erwähnt werden (eine einfache Antwort an
14 | den Bot reicht also nicht: der sichtbare Text des Toots muss
15 | „__@\_ds\_100__“ enthalten!) und der Hashtag __\#folgenbitte__ erwähnt
16 | werden. (Die Kleinschreibung bei diesem Hashtag ist wichtig!)
17 |
18 | Ähnlich kann der Bot auch dazu gebracht werden, automatisch wieder zu
19 | entfolgen. Hierfür muss der Hashtag __\#entfolgen__ (wieder: klein
20 | geschrieben!) mit einer expliziten Erwähnung verbunden werden.
21 |
22 | Zu beiden Aktionen gibt der Bot keine eigene Rückmeldung; ob der Vorgang
23 | erfolgreich war, muss selbsttätig über die eigenen Social Media-Kanäle
24 | herausgefunden werden.
25 |
26 | Der Bot gibt auch darüber Auskunft, welchen Nutzer\*innen-spezifischen
27 | Magic Hashtag er standardmäßig verwendet; dafür muss er mit dem Hashtag
28 | __\#showdefault__ zusammen (explizit) erwähnt werden.
29 |
--------------------------------------------------------------------------------
/doc/links.snip:
--------------------------------------------------------------------------------
1 |
2 |
Navigation schließen
3 |
44 |
45 |
--------------------------------------------------------------------------------
/doc/mastodon-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baeuchle/ds100bot/1a76be55a87de7793e37ea25d248d1d904843e11/doc/mastodon-icon.png
--------------------------------------------------------------------------------
/doc/motivation.md:
--------------------------------------------------------------------------------
1 |
2 |
DS-100: Motivation
3 | Warum gibt es diesen Bot?
4 |
5 |
6 | Motivation
7 | ==========
8 |
9 | Dieser Bot wurde motiviert durch die Unfähigkeit des Social Media Teams eines
10 | großen Deutschen Eisenbahnunternehmens, mit Menschen zu kommunizieren, die
11 | effizienterweise gerne DS100-Kürzel einsetzen wollten, um Betriebsstellen nicht
12 | ausschreiben zu müssen und trotzdem eindeutig benennen zu können.
13 |
14 | Den Ärger darüber, dass nicht nur Unverständnis geäußert wurde, sondern sogar
15 | Menschen dafür getadelt wurden, diese Kürzel zu benutzen („es könnten ja auch
16 | Menschen mitlesen, die das dann nicht verstehen“), leitete der Autor des Bots
17 | in dessen Erstellung um und machte somit etwas Konstruktives, anstatt sich
18 | weiter zu ärgern.
19 |
--------------------------------------------------------------------------------
/doc/script.js:
--------------------------------------------------------------------------------
1 | function toggle_show(element) {
2 | var calculated_class_name = "only-" + element.value;
3 | var calculated_display = element.checked ? "initial" : "none";
4 | console.log(calculated_class_name + ": " + calculated_display);
5 | all_elements = document.getElementsByClassName(calculated_class_name);
6 | for (var i = 0; i < all_elements.length; ++i) {
7 | all_elements[i].style.display = calculated_display;
8 | }
9 | }
10 |
11 | function toggle_menu() {
12 | toggle_any("sidenavi");
13 | }
14 |
15 | function toggle_any(classname) {
16 | var elements = document.getElementsByClassName(classname);
17 | for (var i = 0; i < elements.length; ++i) {
18 | elements[i].classList.toggle("shownnavi");
19 | elements[i].classList.toggle("hiddennavi");
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/doc/twitter-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baeuchle/ds100bot/1a76be55a87de7793e37ea25d248d1d904843e11/doc/twitter-icon.png
--------------------------------------------------------------------------------
/ds100bot:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | """Twitter-Bot für die Expansion Abkürzungen"""
4 |
5 | import argparse
6 | import configparser
7 | import logging
8 |
9 | from AnswerMachine import handle_list
10 | from Externals import setup_database, set_arguments, setup_network, test_network_arguments
11 | import Persistence
12 |
13 | logger = Persistence.init_logger()
14 |
15 | if __name__ == "__main__":
16 | parser = argparse.ArgumentParser(description=__doc__)
17 | Persistence.set_logging_args(parser)
18 | set_arguments(parser)
19 | parser.add_argument('--no-version',
20 | dest='notify_version',
21 | help='Do not send out version status and do not store last version',
22 | required=False,
23 | action='store_false',
24 | default=True)
25 | args = parser.parse_args()
26 | configuration = configparser.ConfigParser()
27 | configuration.read(args.config)
28 | args.config = configuration
29 | network_name = test_network_arguments(args)
30 | logger.setLevel(getattr(logging, args.log_level))
31 | logger.debug("%s bot running args: %s", network_name, args)
32 | logging.getLogger('msg').setLevel(getattr(logging, args.log_level))
33 | try:
34 | database = setup_database(args, network_name)
35 | network = setup_network(network_name, args, Persistence.get_since_id(database))
36 | if args.notify_version:
37 | Persistence.notify_new_version(network, database)
38 |
39 | magic_tags, magic_emojis = database.magic_hashtags()
40 | handle_list(network=network,
41 | database=database,
42 | magic_tags=magic_tags,
43 | magic_emojis=magic_emojis)
44 | if args.notify_version:
45 | Persistence.store_version(database)
46 | Persistence.store_since_id(database, network)
47 | database.close_sucessfully()
48 | except BaseException as be:
49 | logger.exception("Failure for network %s", network_name)
50 | raise SystemExit(1) from be
51 | logger.info("Bot finished")
52 |
--------------------------------------------------------------------------------
/sources/README.md:
--------------------------------------------------------------------------------
1 | Datenlisten
2 | ===========
3 |
4 | Das Quelltextverzeichnis sources/ enthält die Datenlisten, die für den
5 | Bot importiert werden. Diese Datenlisten werden in den Konfigurationen
6 | in data/ referenziert.
7 |
8 | Die Listen sind im CSV-Format; die erste Zeile enthält die Spaltennamen,
9 | die in der Konfiguration (siehe Verzeichnis data/) den Datenbank-Spalten
10 | zugeordnet werden.
11 |
12 | Die Dateien sind in UTF-8 codiert und haben keine Byte-Order Mark.
13 |
14 | Jeder einzelne Datensatz sollte als Antwort in einen Tweet passen, das
15 | heißt für eine Datenquelle mit Default-Quellenangabe 'XS' gilt für einen
16 | Datensatz mit Abkürzung ABK, dass der Langname 272 Zeichen lang sein
17 | darf, weil ``XS#ABK: `` eben 8 Zeichen lang ist:
18 | ``XS#ABK: _HIER_PASSEN_NOCH_272_ZEICHEN_REIN_``.
19 |
20 | Vorsicht jedoch: Twitter zählt manche Zeichen doppelt. Das betrifft
21 | allerdings 'nur' sehr ausgefallene Satzzeichen und nicht-europäische
22 | Alphabete. [Siehe hier für
23 | Details](https://developer.twitter.com/en/docs/basics/counting-characters).
24 |
--------------------------------------------------------------------------------
/sources/faq.csv:
--------------------------------------------------------------------------------
1 | Abk;Name
2 | LEERZEICHEN;Leerzeichen in offiziellen Kürzeln müssen durch _ ersetzt werden. Abkürzungen mit Leerzeichen zu erkennen, widerspricht #NOSPAM. Leerzeichen weglassen wird uneindeutig: https://ds100.frankfurtium.de/leerzeichen_ds100.html
3 | GROSSKLEIN;Groß- und Kleinbuchstaben müssen wie in der jeweiligen Quelle benutzt werden, z.B. ALLES GROß für die DS100.
4 | SIGNAL;Signallisten werden mit % aktiviert. Zum Merken denke man an ein Form-%Vr2, das so ein bisschen wie ein % aussieht.
5 | STRECKE;Streckenlisten werden mit $ aktiviert, z.B. $1733
6 | LINIE;Linienlisten werden mit / aktiviert, z.B. /ICE20
7 | MAGICCHAR;Je nach Art der Abkürzungslisten werden unterschiedliche Anfangszeichen benutzt: # für Orte, $ für Strecken, % für Signale, / für Linien, & für andere Abkürzungen.
8 | STELLWERK;Auf Stellwerken stehen oft Abkürzungen. Diese sind meistens aus Anfangsbuchstaben des Ortes + "f" oder "w" gebildet: *F*ahrdienstleiterin und *W*ärterin. Die Abkürzungen sind höchstens in der direkten Umgebung eindeutig und nicht im Bot hinterlegt.
9 | WIEDERHOLUNG;Der Bot beantwortet jeden Tweet, in dem etwas Beantwortbares ist, auch wenn er den Tweet davor auch schon mit dem gleichen Kürzel beantwortet hat. Threads erkennen und auf Wiederholungen nicht mehr zu reagieren, ist sehr aufwändig, daher bleibt das vorerst so.
10 | REPLY;Der Bot findet ungekennzeichnete Tweets von Accounts, denen er folgt, nicht, wenn diese Tweets auf jemanden Antworten, dem der Bot *nicht* folgt, genauso, wie man solche Tweets in seiner eigenen Timeline auch nicht sieht. Mit Markierung (@_ds_100 oder #DS100) klappt's.
11 | USAGE;Expansion von DS100- und anderen Kürzeln. https://ds100.frankfurtium.de/\n#DS100 im Tweet und Kürzel als Hashtag markieren, bspw #FF\nDetails https://ds100.frankfurtium.de/finde-lang.html
12 | BILDERKENNUNG;Der Bot kann keine Bilderkennung. Wenn er manchmal zu wissen scheint, was auf einem Bild zu sehen ist, weiß er stattdessen, was im Alt-Text zu dem Bild steht. Siehe auch #KI.
13 | DARFICH;Ja, du darfst diesen Bot benutzen, wenn du kein Nazi bist. Siehe #TERMS. #FCKNZS #NAZISRAUS
14 | QUELLENWAHL;Der Bot findet alle Tweets mit Magic Hashtag [MHT] (z.B. #_CH für 🇨🇭, dann wird aus #BN Bern). Mit anderem MHT, z.B. #DS100/Erwähnung, @_ds_100/Antwort, in der der Bot erwähnt wird, kann man #CH:BN benutzen. Siehe auch #FAQ:USERDMT
15 | STANDARDQUELLE;Bei Folgenlassen/Erwähnen interpretiert der Bot Hashtags laut Profil (siehe #FAQ:USERDMT) oder wie #HE als 🇩🇪 (= DS100-Abkürzung). Für andere Quelle (Bsp: DIDOK aus 🇨🇭): Magic Hashtag benutzen (#_CH #HE) oder Quellenkürzel dazu (#CH:HE)
16 | WARTEHALT;Wenn ich kurz gelaufen bin, muss ich mich verschnaufen. Das dauert immer exakt 3 Minuten. Schneller Antworten ist also nicht, warte halt mal ein bisschen.
17 | WASISTDS100;Kürzel der DS100 bestehen aus 1 Buchstabe f Region (hAmbg, Berlin, Dresden, Essen, Ffm, Hann, Köln, haLle, München, Nürnbg, kaRlsr, Saarbrck, sTuttgart, erfUrt, schWerin. I,Q,V,Y s. #FAQ:SONDERGRUPPEN, X,Z s. #FAQ:AUSLAND) und 1-4 Buchstaben für Betriebsstelle.
18 | SONDERGRUPPEN;Kürzel der DS100 mit I,Q,V und Y sind Sondergruppen (siehe #FAQ:WASISTDS100): I=16,7-Hz-Strominfrastruktur, Q=50Hz-Infrastruktur, V=Tankanlagen, Y=Grenzpunkte (Streckenwechsel / Regionalbereiche)
19 | AUSLAND;Kürzel mit X und Z haben als zweiten Buchstaben das Land: XA🇦🇹 XB🇧🇪 XC🇷🇺 XD🇩🇰 XE🇪🇸 XF🇫🇷 XG🇬🇷 XH🇫🇮 XI🇮🇹 XJ🇷🇸 XK🇬🇧 XL🇱🇺 XM🇭🇺 XN🇳🇱 XO🇳🇴 XP🇵🇱 XQ🇹🇷 XR🇭🇷 XS🇨🇭 XT🇨🇿 XU🇷🇴 XV🇸🇪 XW🇧🇬 XX🇵🇹 XY🇸🇰 XZ🇸🇮 ZA🇲🇰 ZB🇧🇦 ZE🇪🇪 ZI🇮🇪 ZK🇰🇿 ZL🇱🇹 ZM🇲🇩 ZT🇱🇻 ZU🇺🇦 ZW🇧🇾
20 | ZITAT;Wird der Bot in Antworten oder Zitaten erwähnt oder ist dort ein Magic Hashtag, guckt er auch den zitierten/beantworteten Status an (nur einen, nicht alle im Thread)
21 | USERDMT;Nutzer*innen-spezifische Standardquellen können z.B. durch "mht: #_CH" im Profiltext eingestellt werden, siehe auch https://ds100.frankfurtium.de/finde-listen.html. Der Bot sagt, was er tut, bei "@_ds_100 #showdefault".
22 |
--------------------------------------------------------------------------------
/sources/linien_bhvbus.csv:
--------------------------------------------------------------------------------
1 | Linie;Laufweg
2 | 501;Wulsdorf Bahnhofstr. - Grünhöfe - Hauptbahnhof - Elbinger Platz - Weserfähre - Stadtverwaltung - Parkstr. - Leherheide West (Schnellbus)
3 | 502;Leherheide West - Parkstr. - Flötenkiel - Lehe - Havenwelten - Hauptbahnhof - Humboldtschule - Grünhöfe
4 | 503;Surheide - Hauptbahnhof - Elbinger Platz - Stadtverwaltung - Flötenkiel - Leherheide West
5 | 504;Hauptbahnhof - Konrad-Adenauer-Platz - Fischereihafen - Bohmsiel - IKEA
6 | 505;Gewerbegebiet Debstedt - Langen Mitte - Hinschweg - Flötenkiel - Lehe - Rotersand - Havenwelten - Hauptbahnhof - Wulsdorf - IKEA
7 | 506;SZ Langen - Langen Mitte - Flötenkiel - Lehe - Rotersand - Havenwelten - Wulsdorf - Wulsdorf Bahnhofstr.
8 | 507;Bramel - Schiffdorf - Hauptbahnhof - Elbinger Platz - Stadtverwaltung - Bahnhof Lehe - Spaden
9 | 508;Klinikum Bremerhaven - Hauptbahnhof - Havenwelten - Lehe - Bahnhof Lehe - Leherheide West
10 | 509;Langen -/Imsum Ort - Weddewarden - Flötenkiel - Stadtverwaltung - Havenwelten - Hauptbahnhof - Surheide
11 | 510;Am Seedeich - Fähranleger - Elbinger Platz - Hauptbahnhof
12 | 511;Bohmsiel - Wulsdorf - Weserfähre - Rotersand - Lehe - Gesundheitsamt - Parkstr. - Ahornweg - Leherheide West (Schnellbus)
13 | 512;(ALT) Weddewarden Überseering - Überseehafen - Rotersand
14 | 513;ALT Leherheide Louise-Schroeder-Str. - Plätternweg
15 | 515;ALT Stadtverwaltung - Buschkämpen
16 | 516;ALT Bohmsiel - Labradorhafen - Seewindstr.
17 | 517;ALT Surheide - Veerenholzstr.
18 | HL;Hafen-Liner: Thünen-Institut - Fischereihafen - Konrad-Adenauer-Platz - Hauptbahnhof - Elbinger Platz - Havenwelten - Neuer Hafen - Rotersand
19 | ML;Moon-Liner: Leherheide - Parkstr. - Lehe - Rotersand - Elbinger Platz - Hauptbahnhof - Humboldtschule - Wulsdorf - Surheide - Hauptbahnhof
20 | NL;Night-Liner: Debstedt - Langen Mitte - Parkstr. - Stadtverwaltung - Havenwelten - Hauptbahnhof - Konrad-Adenauer-Platz - Wulsdorf - Bohmsiel
21 | E11;Debstedt - Langen Mitte - Parkstr. - Flötenkiel - Stadtverwaltung - Hauptbahnhof - Gymnasium Wesermünde
22 | E13;Schiffdorf - Veerenholzstr. - Gymnasium Wesermünde
23 | E16;Leherheide West - Parkstr. - SZ Carl v. Ossietzky
24 |
--------------------------------------------------------------------------------
/sources/linien_dd.csv:
--------------------------------------------------------------------------------
1 | Linie,Laufweg
2 | S1,Schöna – Bad Schandau – Pirna – Dresden – Coswig – Meißen Triebischtal
3 | S2,Pirna – Heidenau – Dresden Hbf – Dresden Flughafen
4 | S3,Dresden – Tharandt – Klingenberg-Colmnitz – Freiberg (Sachs)
5 | 1,Prohlis – Dobritz – Gruna – Stadtzentrum – Friedrichstadt – Leutewitz
6 | 2,Kleinzschachwitz – Leuben – Gruna – Stadtzentrum – Bahnhof Mitte – Cotta – Gorbitz
7 | 3,Coschütz – Plauen – Hauptbahnhof – Stadtzentrum – Bahnhof Neustadt – Wilder Mann
8 | 4,Laubegast – Tolkewitz – Striesen – Stadtzentrum – Mickten – Radebeul – Coswig – Weinböhla
9 | 6,Niedersedlitz – Leuben – Laubegast – Blasewitz – Johannstadt – Neustadt – Bahnhof Mitte – Löbtau – Wölfnitz
10 | 7,Weixdorf – Klotzsche – Neustadt – Stadtzentrum – Hauptbahnhof – Bahnhof Mitte – Cotta – Gorbitz – Pennrich
11 | 8,Hellerau – Neustadt – Stadtzentrum – Hauptbahnhof – Südvorstadt
12 | 9,Prohlis – Reick – Strehlen – Hauptbahnhof – Stadtzentrum – Mickten – Kaditz
13 | 10,Striesen – Pohlandplatz – Straßburger Platz – Hauptbahnhof – MESSE DRESDEN
14 | 11,Bühlau – Bahnhof Neustadt – Stadtzentrum – Hauptbahnhof – Zschernitz
15 | 12,Striesen – Blasewitz – Fetscherplatz – Stadtzentrum – Löbtau – Leutewitz
16 | 13,Prohlis – Reick – Strehlen – Straßburger Platz – Neustadt – Mickten (-Kaditz)
17 | 61,Weißig/Fernsehturm – Bühlau – Blasewitz – Gruna – Strehlen – Südvorstadt – Löbtau
18 | 62,Johannstadt – Stadtzentrum – Südvorstadt – Löbtau Süd – Naußlitz – Dölzschen
19 | 63,Pillnitz – Loschwitz – Blasewitz – Striesen – Strehlen – Mockritz – Zschernitz – Plauen – Löbtau
20 | 64,Reick – Gruna – Striesen – Universitätsklinikum – Waldschlößchen – Neustadt – Pieschen – Mickten – Kaditz
21 | 65,Heidenau/Luga – Leuben – Reick – Seidnitz – Blasewitz
22 | 66,Lockwitz/Nickern – Prohlis – Strehlen – Hauptbahnhof – Südhöhe – Mockritz/Coschütz (- Freital)
23 | 68,Goppeln – Leubnitz – Strehlen – Postplatz – Bahnhof Mitte – Friedrichstadt – Cotta – Cossebaude – Niederwartha
24 | 70,Bf. Klotzsche – Hellerau – Trachenberge – Trachau – Mickten - Übigau – Cotta – Gompitz
25 | 72,Klotzsche Infineon – Hellerau – Boxdorf – Radebeul – Altkaditz – ElbePark
26 | 73,Wilder Mann – Döbelner Straße – S-Bahnhof Pieschen – Wurzener Straße
27 | 74,Jägerpark – Waldschlößchen – Marienallee
28 | 76,Justizvollzugsanstalt – S-Bahnhof Pieschen
29 | 77,Klotzsche Infineon – Flughafen (– Industriegebiet Nord | Marsdorf)
30 | 78,(Ottendorf-Okrilla | Radeberg) – Langebrück – Klotzsche – Wilschdorf
31 | 79,Mickten – Übigau
32 | 80,Klotzsche – Wilschdorf – Boxdorf – Wilder Mann – Trachau – Übigau – Cotta – Omsewitz
33 | 81,Bahnhof Neustadt – Liststraße – Wilschdorf
34 | 83,Bonnewitz – Graupa – Pillnitz
35 | 84,Bühlau – Rochwitz – Loschwitz – Blasewitz
36 | 85,Striesen – Gruna – Strehlen – Zschernitz – Plauen – Löbtau Süd
37 | 86,Heidenau – Kleinzschachwitz – Laubegast – Dobritz – Prohlis – Lockwitz – Kreischa
38 | 87,Striesen – Tolkewitz – Seidnitz – Reick – Leubnitz – Mockritz
39 | 88,Kleinzschachwitz – Niedersedlitz – Prohlis – Kauscha
40 | 89,Röhrsdorf – Borthen – Lockwitz – Niedersedlitz
41 | 90,Löbtau – Naußlitz – Pesterwitz – Altfranken – Gompitz
42 | 91,Gompitz – Pennrich – Unkersdorf – Brabschütz – Merbitz – Briesnitz – Cotta
43 | 92,Cotta – Briesnitz – Ockerwitz
44 | 93,Oberwartha – Cossebaude – Mobschatz – Briesnitz – Cotta
45 | 95,Anruflinientaxi: Bahnhof Cossebaude – Gohlis – Bahnhof Cossebaude
46 | 97,Anruflinientaxi: Leutewitz – Zschonergrundmühle
47 | 98A,Weißig – Gönnsdorf – Pappritz – Niederpoyritz
48 | 98B,Weißig – Schönfeld – Rockau – Cunnersdorf – Niederpoyritz
49 | 98C,Schönfeld – Borsberg
50 |
--------------------------------------------------------------------------------
/sources/linien_delbus.csv:
--------------------------------------------------------------------------------
1 | Linie;Laufweg
2 | 201;Bremen-Huchting - Heidkrug - Bahnhof/ZOB - Markt - Hasport - Annenheide
3 | 202;Deichhorst Hilversumer Str. - Markt - Bahnhof/ZOB - Lange Str. - Brendel - Annenheide - Hasport
4 | 203;Deichhorst Hanse-Wissenschaftskolleg - Neue Str. - Bahnhof/ZOB - Lange Str. - Berliner Str. - Hasport (- Annenheide)
5 | 204;Bremen-Huchting - Varrel - Stickgras - Bahnhof/ZOB - Markt - Düsternort - Brendel Jenaer Str./- Adelheide
6 | 205;Bungerhof - Nordstr. - Bahnhof/ZOB - Markt - Brendel Gothaer Str.
7 | 206;Bungerhof - Scheffelstr. - Bahnhof/ZOB - Markt - Berufsschule - Deichhorst Hanse-Wissenschaftskolleg
8 | 207;Hasbergen -/Alrusch - Dreilinien - Wendenstr. - Bahnhof/ZOB - Bergfeld - Elmeloh/- Wichernstift
9 | 212;Dreilinien - Wendenstr. - Museum - Bahnhof/ZOB - Markt - Brendel - Annenheide
10 | 213;Dwoberg - Bergfeld - Bahnhof/ZOB - Markt - Berliner Str. - Stickgras
11 | 214;Bremen-Huchting - Varrel - Heidkrug - Stickgras - Museum - Bahnhof/ZOB
12 | 215;Bungerhof - Scheffelstr. - Bahnhof/ZOB - Lange Str. - Brendel Gothaer Str.
13 | 216;Deichhorst Hilversumer Str. - Hanse-Wissenschaftskolleg - Markt - Bahnhof/ZOB - Lange Str. - Hasport
14 | 218;Wichernstift - Berufsschule - Bahnhof/ZOB - Lange Str. - Düsternort - Adelheide
15 |
--------------------------------------------------------------------------------
/sources/linien_koeln.csv:
--------------------------------------------------------------------------------
1 | Linie;Laufweg
2 | 1;Weiden West – Junkersdorf – Müngersdorf – Aachener Str./Gürtel – Rudolfplatz – Neumarkt – Bf Deutz – Kalk – Höhenberg – Merheim – Brück – Refrath – Bensberg
3 | 3;Görlinger-Zentrum – Mengenich – Bocklemünd – Bickendorf – Ehrenfeld – Bf West – Friesenplatz – Neumarkt – Bf Deutz – Buchforst – Buchheim – Holweide – Dellbrück – Thielenbruch
4 | 4;Bocklemünd – Bickendorf – Ehrenfeld – Bf West – Friesenplatz – Neumarkt – Bf Deutz – Mülheim Wiener Platz – Höhenhaus – Dünnwald – Schlebusch
5 | 5;Am Butzweilerhof – Neuehrenfeld – Bf West – Friesenplatz – Dom/Hbf – Rathaus – Heumarkt (Teilstrecke: Nord-Süd-Stadtbahn)
6 | 7;Frechen – Marsdorf – Lindenthal – Aachener Str./Gürtel – Rudolfplatz – Neumarkt – Deutz – Poll – Westhoven – Ensen – Porz – Zündorf
7 | 9;Sülz – Universität – Bf Süd – Neumarkt – Bf Deutz – Kalk – Vingst – Ostheim – Königsforst
8 | 12;Merkenich – Niehl – Weidenpesch – Nippes – Ebertplatz – Friesenplatz – Rudolfplatz – Barbarossaplatz – Zollstock
9 | 13;Gürtelbahn: Sülzgürtel – Lindenthal – Aachener Str./Gürtel – Ehrenfeld – Neuehrenfeld – Bilderstöckchen – Nippes – Amsterdamer Str./Gürtel – Mülheim Wiener Platz – Bf Mülheim – Buchheim – Holweide Vischeringstr.
10 | 15;Chorweiler – Heimersdorf – Longerich – Weidenpesch – Nippes – Ebertplatz – Friesenplatz – Rudolfplatz – Barbarossaplatz – Chlodwigplatz – Ubierring
11 | 16;Rheinuferbahn: Niehl Sebastianstr. – Amsterdamer Str./Gürtel – Ebertplatz – Dom/Hbf – Neumarkt – Barbarossaplatz – Chlodwigplatz – Ubierring – Bayenthal – Rodenkirchen – Sürth – Godorf – Wesseling – Hersel – Bonn Hbf – Bonn-Bad Godesberg
12 | 17;Nord-Süd-Stadtbahn: Severinstr. – Chlodwigplatz – Rodenkirchen (– Sürth)
13 | 18;Vorgebirgsbahn: Thielenbruch – Dellbrück – Holweide – Buchheim – Bf Mülheim – Mülheim Wiener Platz – Zoo/Flora – Ebertplatz – Dom/Hbf – Neumarkt – Barbarossaplatz – Sülzgürtel – Klettenberg – Hürth – Brühl – Schwadorf – Bornheim – Alfter – Bonn Hbf
14 | E;Sonderzüge - meist zu Karneval oder zu Spielen des @fckoeln
15 |
--------------------------------------------------------------------------------
/sources/linien_mv.csv:
--------------------------------------------------------------------------------
1 | Linie;Name/Laufweg/Betreiber
2 | RE1;Hanse-Express: Hamburg Hbf - Büchen - Hagenow Land - Schwerin Hbf - Bad Kleinen - Rostock Hbf (DB Regio Nordost)
3 | RE2;Wismar - Schwerin Hbf - Ludwigslust - Wittenberge - Berlin Hbf - Lübben (Speewald) - Cottbus Hbf (DB Regio Nordost)
4 | RE3;Stralsund Hbf - Greifswald - Züssow - Anklam - Pasewalk - Angermünde - Eberswalde - Berlin - Jüterbog - Falkenberg (Elster) (DB Regio Nordost)
5 | RE4;Stadttore-Linie: Lübeck Hbf - Bad Kleinen - Güstrow - Neubrandenburg - Pasewalk - Szczecin Główny / Ueckermünde Stadthafen (DB Regio Nordost)
6 | RE5;Rostock Hbf - Güstrow - / Stralsund Hbf - Neubrandenburg - Neustrelitz Hbf - Berlin Hbf - Wünsdorf-Waldstadt - Elsterwerda (/ Finsterwalde (Niederlausitz)) (DB Regio Nordost)
7 | RE7;Stralsund Hbf - Greifswald (DB Regio Nordost)
8 | RE9;Rostock Hbf - Ribnitz-Damgarten West - Velgast - Stralsund Hbf - Bergen auf Rügen - Lietzow - Sassnitz / Ostseebad Binz (ODEG)
9 | RE10;(Rostock Hbf - Ribnitz-Damgarten West - Velgast -) Stralsund Hbf - Greifswald - Züssow (ODEG)
10 | RB11;Wismar - Neubukow - Bad Doberan - Rostock Hbf - Sanitz - Tessin (DB Regio Nordost)
11 | RB12;(Bad Doberan -) Rostock Hbf - Rövershagen - Graal-Müritz / (Ribnitz-Damgarten West) (DB Regio Nordost)
12 | RB13;Rehna - Gadebusch - Schwerin Hbf- Crivitz - Parchim (ODEG)
13 | RB14;Hagenow Stadt - Hagenow Land - Ludwigslust - Neustadt-Glewe - Parchim (ODEG)
14 | RB15;Waren (Müritz) - Jabel (Meckl) - Inselstadt Malchow (- Karow (Meckl)) (HANS)
15 | RB16;Kleinseenbahn: Neustrelitz Hbf - Wesenberg - Mirow (HANS)
16 | RB17;(Rostock Hbf) / Wismar - Bad Kleinen - Schwerin Hbf - Ludwigslust (DB Regio Nordost)
17 | RB18;Bad Kleinen - Schwerin Hbf (DB Regio Nordost)
18 | RB19;Parchim - Lübz - Karow (Meckl) - Plau am See (ODEG)
19 | RB23;Züssow - Wolgast - Zinnowitz - Seebad Heringsdorf - Świnoujście Centrum (DB Regio Nordost)
20 | RB24;Zinnowitz - Karlshagen - Peenemünde (DB Regio Nordost)
21 | RB25;Velgast - Barth (DB Regio Nordost)
22 | RB26;Zu(g)bringer: Bergen auf Rügen - Putbus - Lauterbach Mole (PRESS)
23 | RB31;Molli: Bad Doberan - Heiligendamm - Ostseebad Kühlungsborn West (Mecklenburgische Bäderbahn Molli)
24 | RB32;Rasender Roland: Lauterbach Mole - Putbus - Binz LB - Sellin Ost - Baabe - Göhren (Rügen) (PRESS)
25 | RB74;(Pritzwalk West -) Pritzwalk - Brügge (Prignitz) - Meyenburg (- Plau am See) (HANS)
26 | S1;S-Bahn Rostock: Warnemünde - Rostock-Lütten Klein - Rostock-Marienehe - Rostock Hbf (DB Regio Nordost)
27 | S2;S-Bahn Rostock: Warnemünde - Rostock-Lütten Klein - Rostock-Marienehe - Rostock Hbf - Schwaan - Güstrow (DB Region Nordost)
28 | S3;S-Bahn Rostock: Warnemünde - Rostock-Lütten Klein - Rostock-Marienehe - Rostock Hbf - Laage (Meckl) - Priemerburg - Güstrow (DB Regio Nordost)
29 |
--------------------------------------------------------------------------------
/sources/linien_ni.csv:
--------------------------------------------------------------------------------
1 | Linie;Laufweg
2 | RE1;Hannover - Nienburg (Weser) - Verden (Aller) - Bremen - Delmenhorst - Oldenburg (Oldb) - Leer (Ostfriesl) - Emden - Norddeich
3 | RE2;Uelzen - Celle - Hannover - Sarstedt - Kreiensen - Northeim (Han) - Göttingen
4 | RE3;Hamburg - Lüneburg - Uelzen - Celle - Hannover
5 | RE4;Hamburg - Buchholz (Nordh) - Rotenburg (Wümme) - Bremen
6 | RE5;Hamburg - Buxtehude - Stade - Cuxhaven
7 | RE8;Hannover - Nienburg (Weser) - Verden (Aller) - Bremen - Osterholz-Scharmbek - Bremerhaven
8 | RE9;Bremerhaven - Osterholz-Scharmbek - Bremen - Diepholz - Osnabrück
9 | RE10;Bad Harzburg - Goslar - Salzgitter-Ringelheim - Hildesheim - Hannover
10 | RE15;Emden - Leer (Ostfriesl) - Meppen - Lingen (Ems) - Rheine - Münster (Westf)
11 | RE18;Wilhelmshaven - Oldenburg (Oldb) - Cloppenburg - Bramsche - Osnabrück
12 | RE19;Wilhelmshaven - Oldenburg (Oldb) - Delmenhorst - Bremen
13 | RE20;Uelzen - Salzwedel - Hohenwulsch - Stendal - Tangerhütte - Magdeburg
14 | RE21;Goslar - Vienenburg - Wernigerode - Halberstadt - Oschersleben (Bode) - Magdeburg
15 | RE30;Wolfsburg - Gifhorn - Lehrte - Hannover
16 | RE50;Wolfsburg - Braunschweig - Hildesheim
17 | RE60;Braunschweig - Peine - Hannover - Minden (Westf) - Melle - Osnabrück - Rheine
18 | RE70;Braunschweig - Peine - Hannover - Minden (Westf) - Herford - Bielefeld
19 | RE78;Nienburg (Weser) - Minden (Westf) - Herford - Bielefeld
20 | RE83;Lüneburg - Büchen - Lübeck - Kiel
21 | RB31;Hamburg - Maschen - Lüneburg
22 | RB32;Lüneburg - Dahlenburg - Dannenberg
23 | RB33;Buxtehude - Bremervörde - Bremerhaven - Dorum - Cuxhaven
24 | RB35;Wolfsburg - Oebisfelde - Gardelegen - Stendal
25 | RB36;Wolfsburg - Oebisfelde - Wegenstedt - Haldensleben - Barleben - Magdeburg
26 | RB37;Bremen - Langwedel - Soltau - Uelzen
27 | RB38;Bucholz (Nordh) - Soltau - Walsrode - Hannover
28 | RB40;Braunschweig - Helmstedt - Eilsleben - Magdeburg - Burg
29 | RB41;Hamburg - Buchholz (Nordh) - Tostedt - Scheeßel - Rotenburg (Wümme) - Bremen
30 | RB42;Braunschweig - Wolfenbüttel - Vienenburg - Bad Harzburg
31 | RB43;Braunschweig - Wolfenbüttel - Vienenburg - Goslar
32 | RB44;Braunschweig - Salzgitter-Immendorf - Salzgitter-Lebenstedt
33 | RB45;Braunschweig - Wolfenbüttel - Schöppenstedt
34 | RB46;Braunschweig - Seesen - Herzberg (Harz)
35 | RB47;Braunschweig - Gifhorn - Wittingen - Uelzen
36 | RB48;Braunschweig - Salzgitter-Lebenstedt
37 | RB56;Bad Bentheim - Nordhorn - Neuenhaus
38 | RB57;Leer - Weener - Nieuweschanz - Groningen
39 | RB58;Osnabrück - Bramsche - Vechta - Delmenhorst - Bremen
40 | RB59;Wilhelmshaven - Sande - Jever - Wittmund - Esens
41 | RB61;Bielefeld - Herford - Bünde - Osnabrück - Rheine - Bad Bentheim - Hengelo
42 | RB65;Bad Bentheim - Nordhorn - Neuenhaus
43 | RB66;Osnabrück - Hasbergen - Lengerich - Münster (Westf)
44 | RB75;Osnabrück - Dissen-Bad Rothenfelde - Halle (Westf) - Bielefeld
45 | RB77;Hildesheim - Hameln - Löhne - Bünde
46 | RB79;Hildesheim - Bodenburg
47 | RB80;Göttingen - Nordheim - Herzberg (Harz) - Nordhausen
48 | RB81;Bodenfelde - Northeim - Herzberg (Harz) - Nordhausen
49 | RB82;Göttingen - Northeim - Kreiensen - Seesen - Goslar - Bad Harzburg
50 | RB84;Kreiensen - Holzminden - Höxter - Ottbergen - Paderborn
51 | RB85;Göttingen - Bodenfelde - Ottbergen - Paderborn
52 | RB86;Göttingen - Northeim - Einbeck-Salzderhelden - Einbeck
53 | RB83;Göttingen - Eichenberg - Hann Münden - Kassel
54 | RB87;Göttingen - Eichenberg - Bebra - Bad Hersfeld - Fulda
55 | S1;Minden (Westf) - Stadthagen - Wunstorf - Hannover - Weetzen - Haste
56 | S2;Nienburg (Weser) - Wunstorf - Hannover - Weetzen - Haste
57 | S3;Hildesheim - Lehrte - Hannover
58 | S4;Hildesheim - Sarstedt - Hannover Messe/Laatzen - Hannover - Langenhagen - Bennemühlen
59 | S5;Hannover Flughafen - Langenhagen - Hannover - Bad Pyrmont - Altenbeken - Paderborn
60 | S6;Celle - Burgdorf - Hannover
61 | S7;Celle - Burgdorf - Lehrte - Hannover
62 | RS1;Verden (Aller) - Achim - Bremen - Bremen-Vegesack - Bremen-Farge
63 | RS2;Bremerhaven-Lehe - Osterholz-Scharmbeck - Ritterhude - Bremen - Twistringen
64 | RS3;Bremen - Delmenhorst - Hude - Oldenburg (Oldb) - Bad Zwischenahn
65 | RS4;Bremen - Delmenhorst - Hude - Nordenham
66 | RS6;Rotenburg (Wümme) - Verden (Aller)
67 |
--------------------------------------------------------------------------------
/sources/linien_no.csv:
--------------------------------------------------------------------------------
1 | Linje;Vei
2 | F1;Oslo - Karlstad - Stockholm
3 | F4;Bergensbane: Oslo S - Drammen - Finse - Myrdal - Voss - Arna - Bergen
4 | F5;Sørlandsbana: Oslo - Drammen - Kongsberg - Nelaug - Kristiansand - Egersund - Stavanger
5 | F6;Dovrebane: Oslo - Hamar - Lillehammer - Dombås- Støren - Trondheim S
6 | F7;Nordlandsbane: Trondheim - Steinkjer - Mosjøen - Rognan - Bodø
7 | F8;Ofotbane: Narvik - Bjørnfjell (- Kiruna)
8 | FLY1;Flytoget: Drammen - Oslo S - Lillestrøm - OSL (stopper ikke på Stabekk)
9 | FLY2;Flytoget: Drammen - Stabekk - Oslo S - OSL (stopper ikke på Lillestrøm)
10 | L1;Spikkestad - Asker - Oslo S - Lillestrøm
11 | L2;Stabekk - Oslo S - Ski
12 | L4;Arnabanen: Arna - Bergen
13 | L5;Egersund - Stavanger
14 | RE10;Drammen - Asker - Oslo S - OSL - Eidsvoll - Hamar - Lillehammer (- Dombås)
15 | RE11;Vestfoldbanen: Skien - Larvik - Drammen - Asker - Oslo S - OSL - Eidsvoll
16 | R12;Kongsberg - Frammen - Asker - Oslo S - OSL - Eidsvoll
17 | R13;Drammen - Asker - Oslo S - Lillestrøm - Dal
18 | R14;Asker - Oslo S - Lillestrøm - Kongsvinger
19 | RE20;Østfoldbanen: Göteborg - Halden - Moss - Ski - Oslo S
20 | R21;Moss - Ski - Oslo S
21 | R22;Rakkestad - Mysen - Ski - Oslo S
22 | R23;Follobanen: Ski - Oslo S
23 | RE30;Gjøvikbanen: Oslo S - Nittedal - Jaren - Gjøvik
24 | RE31;Gjøvikbanen: Oslo S - Nittedal - Jaren
25 | R40;Vossebana: Myrdal - Voss - Arna - Bergen
26 | R45;Flåmsbana: Myrdal - Flåm
27 | R50;Arendalsbanen: Nelaug - Arendal
28 | R55;Bratsbergbanen: Notodden - Nordagutu - Skien - Porsgrunn
29 | R60;Rørosbanen: Hamar - Røros - Støren - Trondheim S
30 | R65;Raumabana: Dombås - Åndalsnes
31 | R70;(Støren / Lerkendal) - Trondheim S - Steinkjer)
32 | R71;Meråkerbane: Trondheim - Storlien
33 | R75;Rognan - Fauske - Bodø
34 |
--------------------------------------------------------------------------------
/sources/linien_nvs.csv:
--------------------------------------------------------------------------------
1 | Linie;Laufweg
2 | 1;Kliniken - Hauptbahnhof - Marienplatz - Stauffenbergstraße - Berliner Platz - Hegelstraße
3 | 2;Lankow-Siedlung - Platz der Freiheit - Marienplatz - Stauffenbergstraße - Berliner Platz - Hegelstraße
4 | 3;Hegelstraße - Berliner Platz - Stauffenbergstraße - Waldfriedhof - Krebsförden - Neu Pampow
5 | 4;Kliniken - Hauptbahnhof - Marienplatz - Waldfriedhof - Krebsförden - Neu Pampow
6 | 5;Hauptbahnhof P+R - Marienplatz - Görries
7 | 6;Stauffenbergstraße - Freilichtmuseum - Raben Steinfeld, Oberdorf
8 | 7;Hauptbahnhof P+R - Marienplatz - Krebsförden Dorf - Grabenstraße - Krebsförden
9 | 8;Lübstorf - Wickendorf - Kliniken - Hauptbahnhof - Marienplatz - Jugendherberge
10 | 9;Stauffenbergstraße - Am Grünen Tal - Stern Buchholz
11 | 10;Buchenweg - Knaudtstraße - Schloss/Theater - Marienplatz - Hauptbahnhof - Platz der Freiheit - Alter Friedhof - Bleicherufer
12 | 11;Buchenweg - / Kliniken - Walther-Rathenau-Straße - Bergstraße - Schelfmarkt - Hauptbahnhof - Platz der Freiheit - Alter Friedhof - Bleicherufer
13 | 12;Marienplatz - Neumühle - Sacktannen - Wittenförden
14 | 13;Lankow-Siedlung - Sacktannen - Grabenstraße - Krebsförden - Waldfriedhof - Am Grünen Tal - Otto von-Guericke-Straße
15 | 14;Lankow-Siedlung - Neumühle - Marienplatz - Jugendherberge
16 | 16;Kantstraße - Am Grünen Tal - Waldfriedhof - Krebsförden - Grabenstraße - Görries
17 | 17;Friedrichsthal - Lankow-Siedlung - Kieler Straße
18 | 18;Friedrichsthal - Lankow-Siedlung - Kieler Straße - Margaretenhof - Alte Gärtnerei - Pingelshagen
19 | 19;Hauptbahnhof P+R - Marienplatz - Betriebshof NVS
20 | 20;Stauffenbergstraße - Göhrener Tannen
21 |
--------------------------------------------------------------------------------
/sources/linien_nwm.csv:
--------------------------------------------------------------------------------
1 | Linie;Laufweg
2 | 1;Stadtverkehr Wismar: Gägelow - Ostseeblick - Wendorf - Wismar ZOB - Krankenhaus - Friedenshof
3 | 2;Stadtverkehr Wismar: Gägelow - Proseken - Ostseeblick - Wendorf - Krankenhaus - Friedhof - ZOB
4 | 3;Stadtverkehr Wismar: Fischkaten - Philosophenweg - ZOB - Burgwall - Markt - Fischkaten
5 | 4;Stadtverkehr Wismar: Seebad Wendorf - Markt - ZOB - Sporthalle - Krankenhaus - Gartenstadt
6 | 5;Stadtverkehr Wismar: Seebad Wendorf - Burgwall - Markt - Bahnhof
7 | 6;Stadtverkehr Wismar: Kritzow - Dargetzow - ZOB - Westhafen - Burgwall - Kritzow
8 | 30;Stadtverkehr Grevesmühlen
9 | 106;Schwerin - Kl. Trebbow - Drispeth
10 | 107;Schwerin - Alt Meteln - Böken
11 | 110;Schwerin - Brüsewitz - Cramon
12 | 130;Gadebusch - Bobitz - Wismar
13 | 131;Gadebusch - Ratzeburg
14 | 140;Gadebusch - Schwerin
15 | 142;Gadebusch - Mühlen Eichsen - Grevesmühlen
16 | 143;Gadebusch - Mühlen Eichsen - Schwerin
17 | 144;Schwerin - Drieberg - Gadebusch
18 | 145;Gadebusch - Schönberg - Selmsdorf
19 | 146;Gadebusch - Rehna - Carlow - Schlagsdorf
20 | 147;Bentin - Krembz - Gadebusch
21 | 148;Krembz - Lützow - Schwerin
22 | 151;Grambow - Lützow - Gr. Welzin - Gadebusch
23 | 152;Gadebusch - Rosenow
24 | 153;Gadebusch - Lützow - Krembz
25 | 155;Gadebusch - Wakenstädt
26 | 156;Gadebusch - Kneese - Roggendorf - Gadebusch
27 | 158;Schwerin - Gadebusch - Rehna - Schönberg
28 | 160;Rehna - Parber - Törber - Löwitz
29 | 161;Gadebusch - Rehna - Benzin
30 | 162;Gadebusch - Meetzen - Kl. Hundorf - Gadebusch
31 | 163;Gadebusch - Webelsfelde/Frauenmark - Mühlen Eichsen
32 | 200;Wismar - Neukloster
33 | 202;Wismar - Neukloster - Warin - Groß Labenz
34 | 203;Kritzow - Madson Hof
35 | 230;Wismar - Kirchdorf - Timmendorf Strand
36 | 235;Schwerin Hbf - Lübstorf - Wismar
37 | 240;Wismar - Klütz - Boltenhagen - Weiße Wiek
38 | 241;Wismar - Hohen Wieschendorf
39 | 245;Wismar - Neukloster - Warin - Blankenberg
40 | 250;Wismar - Bobitz
41 | 251;Wismar - Beidendorf - Bobitz - Dorf Mecklenburg - Lübow
42 | 254;Rambow - Bobitz
43 | 255;Bobitz - Bad Kleinen
44 | 280;Dorf Mecklenburg - Gallentin
45 | 300;Grevesmühlen - Dassow - Schlutup
46 | 301;Dassow - Schönberg - Selmsdorf
47 | 310;Grevesmühlen - Mühlen Eichsen/Schönhof
48 | 320;Grevesmühlen - Tarnewitz/Redewisch
49 | 321;Klütz - Hohen Schönberg - (Schwansee) - Kalkhorst - Dassow
50 | 322;Klütz - Elmenhorst - Brook
51 | 323;Damshagen - Gutow - Moor/Parin
52 | 325;Weiße Wiek - Boltenhagen - Redewisch
53 | 330;Grevesmühlen - Wismar
54 | 331;Grevesmühlen - Friedrichshagen/Barendorf
55 | 332;Grevesmühlen - Niendorf/Ostsee
56 | 333;Grevesmühlen - Warnow - Damshagen
57 | 335;Grevesmühlen - Dassow - Selmsdorf - Lübeck
58 | 340;Grevesmühlen - Mühlen Eichsen - Schwerin Hbf
59 | 341;Grevesmühlen - Mallentin - Damshagen/Dassow
60 | 342;Grevesmühlen - Menzendorf - Schönberg
61 | 343;Grevesmühlen - Bernstorf - Börzow/Gostorf
62 | 344;Grevesmühlen - Rehna - Schönberg
63 | 345;Grevesmühlen - Klütz - Boltenhagen - Weiße Wiek
64 | 351;Schönberg - Carlow/Cordshagen
65 | 353;Schönberg - Lockwisch
66 | 372;Dassow - Harkensee - Pötenitz
67 | 390;Boltenhagen - Dassow - Schönberg - Herrnburg - Lübeck
68 | 390;Schönberg - Lüdersdorf - Herrnburg
69 | 391;Schattin - Herrnburg
70 | 400;Wismar - Proseken - (Barnekow) - Grevesmühlen
71 | 401;Wismar - Zierow - Proseken
72 | 402;Wismar - Barnekow - Gägelow - Proseken
73 | 410;Neukloster - Lüdersdorf b Neukloster
74 | 411;Kritzow - Neukloster Am Sonnenberg
75 | 412;Wismar - Hornstorf - Krusenhagen
76 | 413;Wismar - Neuburg - Boiensdorf
77 | 420;Wismar - Ventschow
78 | 421;Karow Gewerbepark - Kritzow Gewerbegebiet
79 | 431;Wismar - Boiensdorf
80 | 440;Neukloster - Groß Tessin - Babst - Glasin - Passee
81 | 441;Neukloster - Wakendorf
82 |
--------------------------------------------------------------------------------
/sources/linien_opr.csv:
--------------------------------------------------------------------------------
1 | Linie;Laufweg
2 | 701;Stadtlinie Kyritz: Lindenschule - Untersee
3 | 702;Kyritz - Teetz
4 | 703;Kyritz - Berlitt - Breddin
5 | 704;Kyritz - Blankenberg - Gottberg - Neuruppin
6 | 705;Kyritz - Babe
7 | 706;Kyritz - Joachimshof - Babe
8 | 707;Kyritz - Schönberg (Ky.) - Wulkow (Ky.)
9 | 711;PlusBus Ruppiner Seenland: Kyritz - Wusterhausen - Neuruppin
10 | 712;Kyritz - Zernitz - Neustadt (Dosse)
11 | 713;Neustadt (Dosse) - Wusterhausen - Nackel
12 | 714;Kyritz - Wusterhausen (Dosse) - Neustadt (Dosse)
13 | 715;Neustadt (Dosse) - Sieversdorf - Dreetz
14 | 717;Kyritz - Drewen
15 | 719;Breddin - Zernitz - Neustadt (Dosse)
16 | 740;Stadtlinie Wittstock (Dosse): Alt Daber - Polthierstr.
17 | 741;Wittstock - Gadow - Dossow - Wittstock
18 | 742;Wittstock - Blumenthal - Grabow - Herzsprung
19 | 743;Wittstock - Blesendorf - Heiligengrabe - Wittstock
20 | 744;Wittstock - Königsberg - Herzsprung - Rossow - Kyritz
21 | 745;Wittstock - Freyenstein - Ackerfelde - Meyenburg
22 | 746;Wittstock - Sewekow - Zempow - Flecken Zechlin
23 | 748;Rossow - Neuruppin
24 | 752;Neuruppin - Garz - Wustrau
25 | 754;Neuruppin - Kränzlin - Walsleben - Dannenfeld
26 | 756;PlusBus Ruppiner Seenland: Neuruppin - Fehrbellin
27 | 757;Fehrbellin - Königshorst
28 | 758;Fehrbellin - Linum - Kremmen
29 | 759;Neuruppin - Wildberg
30 | 762;Neuruppin - Gühlen Glienicke - Rägelin - Walsleben
31 | 764;PlusBus Ruppiner Seenland: Neuruppin - Lindow (Mark) - Rheinsberg
32 | 766;Wustrau - Fehrbellin
33 | 770;Stadtlinie Neuruppin: Treskow - Alt Ruppin
34 | 771;Stadtlinie Neuruppin: Alt Ruppin - W.-Rathenau-Str.
35 | 772;Stadtlinie Neuruppin: Rheinsberger Tor Bhf. - Alt Ruppin, Schule
36 | 777;Neuruppin - Rüthnick - Wustrau
37 | 779;Neuruppin - Molchow - Zermützel/Zippelsförde
38 | 782;Wall - Beetz-Sommerfeld
39 | 783;Herzberg (Mark) - Löwenberg
40 | 784;Rheinsberg - Lindow (Mark) - Gransee
41 | 785;Schlösser-Linie: Rheinsberg - Flecken Zechlin - Mirow
42 | 787;Neuruppin - Flecken Zechlin
43 | 788;Rheinsberger Seenbus: Rheinsberg - Großzerlang
44 | 791;Neuruppin - Rüthnick - Herzberg (Mark) - Lindow (Mark)
45 | 792;Lindow (Mark) - Gühlen - Keller - Banzendorf - Hindenberg (OPR)
46 | 794;Tierpark-Heide-Linie: Neuruppin - Gühlen Glienicke - Rheinsberg
47 |
--------------------------------------------------------------------------------
/sources/linien_sh.csv:
--------------------------------------------------------------------------------
1 | Linie;Laufweg
2 | RE1;Hanseexpess: Hamburg Hbf - Schwarzenbek - Müssen - Büchen - Schwerin Hbf - Bad Kleinen - Rostock Hbf
3 | RE4;Lübeck Hbf - Bad Kleinen - Güstrow - Neubrandenburg - Pasewalk - Szczecin Glowny
4 | RE6;Hamburg-Altona - Elmshorn -Glückstadt - Itzehoe - Husum - Niebüll - Westerland (Sylt)
5 | RE7;Hamburg Hbf - Elmshorn - Neumünster < Bordesholm - Kiel | Rendsburg - Schleswig - Flensburg
6 | RE8;Hamburg Hbf - Bad Oldesloe - Reinfeld - Lübeck Hbf - Lübeck-Travemünde Strand
7 | RE60;Sprinter: Hamburg Hbf - Husum - Niebüll - Westerland (Sylt)
8 | RE70;Hamburg Hbf - Elmshorn - Neumünster - Bordesholm - Kiel Hbf
9 | RE72;Kiel Hbf- Eckernförde - Süderbrarup - Flensburg
10 | RE74;Kiel Hbf - Rendsburg - Schleswig - Husum
11 | RE80;Hamburg Hbf - Ahrensburg - Bad Oldesloe - Reinfeld - Lübeck Hbf
12 | RE83;Kiel Hbf - Plön - Eutin - Lübeck Hbf - Ratzeburg - Büchen - Lüneburg
13 | RE84;Sprinter: Hamburg Hbf - Lübeck Hbf - Bad Schwartau - Eutin - Plön - Preetz - Kiel Hbf
14 | RE85;Hamburger Strand-Express: Hamburg Hbf - Ahrensburg - Bad Oldesloe - Lübeck Hbf - Oldenburg (Holst) - Fehmarn-Burg - Puttgarden
15 | RB61;Hamburg Hbf - Pinneberg - Elmshorn - Glückstadt - Itzehoe
16 | RB62;Heide (Holst) - Meldorf - St. Michaelisdonn - Wilster - Itzehoe
17 | RB63;Neumünster - Hohenwestedt - Nordhastedt - Heide (Holst) - Büsum
18 | RB64;Husum - Tönning - Katharinenheerd - Tating - Bad St. Peter-Ording
19 | RB65;Niebüll - Deezbüll - Maasbüll - Dagebüll
20 | RB66;Niebüll - Uphusum - Süderlügum - Tonder - Visby - Rejsby - Esbjerg
21 | RB71;Hamburg-Altona - Pinneberg - Elmshorn - Wrist
22 | RB73;Kiel Hbf - Eckernförde
23 | RB75;Kiel Hbf - Rendsburg
24 | RB76;Kiel Hbf - Kiel-Oppendorf
25 | RB81;Hamburg Hbf - Hamburg-Wandsbek - Ahrensburg - Bargteheide - Bad Oldesloe
26 | RB82;Bad Oldesloe - Bad Segeberg - Neumünster
27 | RB84;Kiel Hbf - Preetz - Plön - Eutin - Bad Schwartau - Lübeck Hbf
28 | RB85;Lübeck Hbf - Bad Schwartau - Scharbeutz - Sierksdorf - Neustadt (Holst)
29 | X85;Lübeck ZOB - Haffkrug - Oldenburg (Holst) - Fehmarn-Burg - Puttgarden
30 | RB86;Lübeck Hbf - Lübeck-Travemünde Strand
31 | A1;Hamburg-Eidelstedt - Ulzburg Süd
32 | A2;Norderstedt Mitte - Kaltenkirchen (Holst) - Neumünster
33 | A3;Elmshorn - Barmstedt - Ulzburg Süd
34 |
--------------------------------------------------------------------------------
/sources/linien_sn.csv:
--------------------------------------------------------------------------------
1 | Linie,Laufweg
2 | RE1,Dresden – Arnsdorf – Bischofswerda – Bautzen – Löbau – Görlitz
3 | RB1,Zwickau Zentrum – Lengenfeld – Falkenstein – Klingenthal – Kraslice
4 | RE2,Dresden – Arnsdorf – Bischofswerda – Ebersbach – Zittau – Liberec
5 | RB2,Zwickau – Plauen – Mehltheuer – Hof / Cheb
6 | RE3,Dresden – Tharandt – Chemnitz – Zwickau – Plauen (Vogtl) – Hof
7 | RE4,Halle (Saale) Hbf – Domnitz (Saalkr) – Könnern – Halberstadt – Goslar
8 | RB4,Gera – Elsterberg – Weischlitz
9 | RB5,Mehltheuer – Plauen – Falkenstein – Kraslice – Karlovy Vary
10 | RE6,Leipzig – Bad Lausick – Geithain – Burgstädt – Chemnitz
11 | RE10,Leipzig Hbf – Eilenburg – Beilrode – Cottbus
12 | RE13,Leipzig Hbf – Delitzsch – Bitterfeld – Dessau Hbf – Zerbst (Anh) – Magdeburg Hbf
13 | RE15,Dresden – Großenhain – Ruhland – Hoyerswerda
14 | RE18,Dresden – Großenhain – Ortrand – Ruhland – Senftenberg – Cottbus
15 | RE19,Dresden – Heidenau – Altenberg (Ski- und Wanderexpress)
16 | RE20,Dresden – Pirna – Bad Schandau – Schöna – Dolní Zleb – Děčín – Ústí n.L. – Litoměřice
17 | RB20,Leipzig Hbf – Weißenfels – Naumburg (Saale) Hbf – Bad Kösen – Großheringen – Erfurt Hbf – Eisenach
18 | RB30,Dresden – Klingenberg-Colmnitz – Freiberg – Chemnitz – Glauchau – Zwickau
19 | RB31,Dresden – Cossebaude – Coswig – Großenhain – Elsterwerda-Biehla
20 | RB33,Dresden – Ottendorf-Okrilla – Königsbrück
21 | RB34,Dresden – Radeberg – Kamenz
22 | RB37,Gößnitz – Glauchau
23 | RE42,Leipzig Hbf – Weißenfels – Naumburg (Saale) Hbf – Jena – Saalfeld – Nürnberg
24 | RB45,Chemnitz – Stauchitz – Riesa – Elsterwerda
25 | RE50,Saxonia: Dresden – Riesa – Leipzig
26 | RB60,Dresden – Arnsdorf – Bischofswerda – Bautzen – Löbau – Görlitz
27 | RB61,Dresden – Arnsdorf – Bischofswerda – Ebersbach – Zittau
28 | RB64,Hoyerswerda – Uhyst – Niesky – Görlitz
29 | RB65,Zittau – Görlitz – Weißwasser – Cottbus
30 | RB71,Pirna – Dürrröhrsdorf – Neustadt – Sebnitz
31 | RB72,Heidenau – Glashütte – Altenberg
32 | RB80,Chemnitz – Flöha – Annaberg-Buchholz – Cranzahl
33 | RB81,Chemnitz – Flöha – Pockau-Lengefeld – Olbernhau-Grünthal
34 | RB89,Chemnitz – Thalheim – Aue (Schienenersatzverkehr mit Bus 361 und 524)
35 | RB95,Zwickau – Aue – Johanngeorgenstadt
36 | RB110,Leipzig – Grimma – Döbeln
37 | RB113,Leipzig – Bad Lausick – Geithain
38 | EBx12,Leipzig Hbf – Zeitz – Wetterzeube – Gera – Saalfeld
39 | EBx13,Gera – Weida – Hof
40 | EB22,Leipzig Hbf – Zeitz – Wetterzeube – Gera – Saalfeld
41 | U28,Rumburk – Šluknov – Sebnitz – Bad Schandau – Děčín
42 | T7,Cranzahl – Vejprty – Chomutov
43 | L7,Rybniště/Seifhennersdorf – Varnsdorf – Zittau – Liberec
44 | CD142|ČD142,Johanngeorgenstadt – Karlovy Vary
45 | CB53,Glauchau – Stollberg (Sachs)
46 | Kirnitzschtalbahn,Bad Schandau Stadtpark – Lichtenhainer Wasserfall
47 | LGB,Radebeul Ost – Radeburg
48 | Lößnitzgrundbahn,Radebeul Ost – Radeburg
49 | WTB,Freital-Hainsberg – Dippoldiswalde – Kurort Kipsdorf
50 | Weißeritztalbahn,Freital-Hainsberg – Dippoldiswalde – Kurort Kipsdorf
51 | Fichtelbergbahn,Cranzahl – Kurort Oberwiesenthal
52 | DSB,Augustusburg – Erdmannsdorf
53 | Drahtseilbahn,Augustusburg – Erdmannsdorf
54 | FEG,Freiberg – Holzhau
55 | Freiberger Eisenbahn,Freiberg – Holzhau
56 | DBG|DBG502|Döllnitzbahn,Oschatz – Mügeln – Altmügeln – Kemmlitz/Glossen
57 | SOEG|Zittauer Schmalspurbahn,Zittau – Bertsdorf – Kurort Oybin/Kurort Jonsdorf
58 | WEM|Waldeisenbahn|Waldeisenbahn Muskau,Weißwasser – Kromlau/Bad Muskau
59 |
--------------------------------------------------------------------------------
/sources/linien_th.csv:
--------------------------------------------------------------------------------
1 | Linie;Laufweg und Betreiber
2 | RE1;Göttingen – Erfurt – Gera – Glauchau (DB)
3 | RE2;Erfurt – Bad Langensalza – Leinefelde – Kassel-Wilhelmshöhe (DB)
4 | RE3;Erfurt – Jena – Gera – Altenburg/Greiz (DB)
5 | RE7;Erfurt – Grimmenthal – Würzburg (DB)
6 | RE14;Saalfeld (Saale) – Bamberg – Nürnberg (DB)
7 | RE18;Jena Göschwitz – Naumburg – Halle (DB)
8 | RE19;Sonneberg – Coburg – Bamberg – Nürnberg (DB)
9 | RE42;Leipzig – Jena – Saalfeld (Saale) – Nürnberg (DB)
10 | RE49;Sonneberg – Coburg – Lichtenfels – Nürnberg (DB)
11 | RE55;Nordhausen – Erfurt (DB)
12 | RE56;Nordhausen – Erfurt (DB)
13 | RB37;Gößnitz – Glauchau (DB)
14 | RB52;Erfurt – Leinefelde (DB)
15 | RB53;Gotha – Bad Langensalza (DB)
16 | RB80;Nordhausen – Göttingen (DB)
17 | S5X;Halle – Leipzig/Halle Flughafen – Leipzig – Altenburg – Zwickau (DB)
18 | S5;Halle – Leipzig – Altenburg – Zwickau (DB)
19 | RE8;Leinefelde – Sangerhausen – Halle (ABRM)
20 | RE9;Kassel – Nordhausen – Sangerhausen – Halle (ABRM)
21 | RE10;Erfurt – Sangerhausen – Magdeburg (ABRM)
22 | RE15;Saalfeld – Jena Saalbf (ABRM)
23 | RE16;Erfurt – Naumburg – Halle (ABRM)
24 | RE17;Erfurt – Naumburg (ABRM)
25 | RB20;Eisenach – Erfurt – Naumburg – Leipzig (ABRM)
26 | RB25;Saalfeld – Jena – Naumburg – Halle (ABRM)
27 | RB51;Heilbad Heiligenstadt – Leinefelde – Nordhausen (ABRM)
28 | RB59;Erfurt – Sangerhausen (ABRM)
29 | RB75;Nordhausen – Sangerhausen – Halle (ABRM)
30 | RE12;Leipzig – Gera – Saalfeld (Saale) (EIB)
31 | RE13;Gera – Zeulenroda unt Bf – Hof (EIB)
32 | RB21;Erfurt – Weimar – Jena – Gera (EIB)
33 | RB22;Leipzig – Gera – Saalfeld (Saale) (EIB)
34 | RB23;Erfurt – Arnstadt – Saalfeld (Saale) (EIB)
35 | RB26;Weimar – Kranichfeld (EIB)
36 | RB27;Sömmerda – Buttstädt (EIB)
37 | RB28;Jena Saalbf – Pößneck unt Bf (EIB)
38 | RB32;Saalfeld (Saale) – Blankenstein (Saale) (EIB)
39 | RB40;Meiningen – Schweinfurt (EIB)
40 | RE45;Erfurt – Ilmenau (STB)
41 | RE50;Erfurt – Zella-Mehlis – Meiningen (STB)
42 | RB41;Eisenach – Meiningen – Eisfeld – Sonneberg – Neuhaus a Rennweg (STB)
43 | RB43;Wernshausen – Schmalkalden – Zella-Mehlis – Suhl (STB)
44 | RB44;Erfurt – Meiningen (STB)
45 | RB46;Erfurt – Ilmenau– Rennsteig (STB)
46 | RB48;Fröttstädt – Friedrichroda (STB)
47 | OBS;Rottenbach – Katzhütte, Obstfelderschmiede – Lichtenhain (Bergbahn), Lichtenhain (Bergbahn) – Cursdorf (OBS)
48 | HSB;Nordhausen – Ilfeld – Drei Annen Hohne (HSB)
49 | RB4;Gera – Greiz – Weischlitz (VBG)
50 | RB6;Eisenach – Bebra (CAN)
51 |
--------------------------------------------------------------------------------
/sources/linien_vab_kreis_ab.csv:
--------------------------------------------------------------------------------
1 | Linie;Start;über 1;über 2;über 3;über 4;über 5;über 6;;Ziel;Anmerkung;Laufweg
2 | 20;Aschaffenburg ROB;Goldbach;Hösbach;Feldkahl;;;;;Schöllkrippen;;Aschaffenburg ROB - Goldbach - Hösbach - Feldkahl - Schöllkrippen
3 | 21;Aschaffenburg ROB;Goldbach;Hösbach-Sand;Wenighösbach;;;;;Unterafferbach;;Aschaffenburg ROB - Goldbach - Hösbach-Sand - Wenighösbach - Unterafferbach
4 | 23;Aschaffenburg ROB;Goldbach;Feldkahl;;;;;;Mömbris;;Aschaffenburg ROB - Goldbach - Feldkahl - Mömbris
5 | 24;Aschaffenburg ROB;Steinbach;Oberafferbach;Rückersbach;Hohl;;;;Mömbris;;Aschaffenburg ROB - Steinbach - Oberafferbach - Rückersbach - Hohl - Mömbris
6 | 25;Aschaffenburg ROB;Johannesberg;Breunsberg;Daxberg;Mömbris;Geiselbach;;;Schöllkrippen;;Aschaffenburg ROB - Johannesberg - Breunsberg - Daxberg - Mömbris - Geiselbach - Schöllkrippen
7 | 26;Mömbris;Rappach;Molkenberg;;;;;;Hemsbach;;Mömbris - Rappach - Molkenberg - Hemsbach
8 | 27;Wiesen;Edelbach;Schöllkrippen;;;;;;Hösbach;;Wiesen - Edelbach - Schöllkrippen - Hösbach
9 | 28;Heigenbrücken;Jakobsthal;Heinrichsthal;Wiesen;Schöllkrippen;;;;Hösbach;;Heigenbrücken - Jakobsthal - Heinrichsthal - Wiesen - Schöllkrippen - Hösbach
10 | 29;Blankenbach;Krombach;Schöllkrippen;;;;;;Vormwald;;Blankenbach - Krombach - Schöllkrippen - Vormwald
11 | 29S;Vormwald;Schöllkrippen;Geiselbach;Krombach;;;;;Blankenbach;;Vormwald - Schöllkrippen - Geiselbach - Krombach - Blankenbach
12 | 30;Schöllkrippen;Westerngrund;Somborn;Bernbach;Horbach;Eidengesäß;;;Gelnhausen;;Schöllkrippen - Westerngrund - Somborn - Bernbach - Horbach - Eidengesäß - Gelnhausen
13 | 31;Aschaffenburg ROB;Kleinostheim Waldstadt;Dettingen;Alzenau;Albstadt;;;;Somborn;;Aschaffenburg ROB - Kleinostheim Waldstadt - Dettingen - Alzenau - Albstadt - Somborn
14 | 32;Kahl;Karlstein;Alzenau;;;;;;Kahl;;Kahl - Karlstein - Alzenau - Kahl
15 | 33;Schöllkrippen;;;;;;;;Aschaffenburg;Kahlgrundexpress;(Kahlgrundexpress) Schöllkrippen - Aschaffenburg
16 | 40;Aschaffenburg ROB;Haibach;Mespelbrunn;;;;;;Dammbach;;Aschaffenburg ROB - Haibach - Mespelbrunn - Dammbach
17 | 41;Aschaffenburg ROB;Bessenbach;;;;;;;Hösbach-Bahnhof;;Aschaffenburg ROB - Bessenbach - Hösbach-Bahnhof
18 | 42;Aschaffenburg ROB;Goldbach;Hösbach;Hösbach Bf.;Waldaschaff;Rothenbuch;;;Weibersbrunn;;Aschaffenburg ROB - Goldbach - Hösbach - Hösbach Bf. - Waldaschaff - Rothenbuch - Weibersbrunn
19 | 43;Aschaffenburg ROB;Haibach;Schmerlenbach;Hösbach Bf.;;;;;Waldaschaff;;Aschaffenburg ROB - Haibach - Schmerlenbach - Hösbach Bf. - Waldaschaff
20 | 44;Aschaffenburg ROB;Goldbach;Hösbach;Laufach;;;;;Hain;;Aschaffenburg ROB - Goldbach - Hösbach - Laufach - Hain
21 | 45;Aschaffenburg ROB;Goldbach;Hösbach;Sailauf;;;;;Eichenberg;;Aschaffenburg ROB - Goldbach - Hösbach - Sailauf - Eichenberg
22 | 47;Aschaffenburg ROB;Haibach;Grünmorsbach;Straßbessenbach;Bessenbach;Keilberg;Hösbach Bf.;Waldaschaff;Rothenbuch;Wochenendverkehr Hochspessart;(Wochenendverkehr Hochspessart) Aschaffenburg ROB - Haibach - Grünmorsbach - Straßbessenbach - Bessenbach - Keilberg - Hösbach Bf. - Waldaschaff - Rothenbuch
23 | 50;Aschaffenburg ROB;Mainaschaff;Kleinostheim;Karlstein;;;;;Kahl;;Aschaffenburg ROB - Mainaschaff - Kleinostheim - Karlstein - Kahl
24 | 52;Großostheim Friedenschule;Großostheim Realschule;Pflaumheim;Wenigumstadt;Ringheim;;;;Stockstadt;Schulverband Großostheim;(Schulverband Großostheim) Großostheim Friedenschule - Großostheim Realschule - Pflaumheim - Wenigumstadt - Ringheim - Stockstadt
25 | 53;Aschaffenburg ROB;;Großostheim;Ringheim;Schaafheim;;;;Babenhausen (Hess.);;Aschaffenburg ROB - Großostheim - Ringheim - Schaafheim - Babenhausen (Hess.)
26 | 54;Aschaffenburg ROB;;Großostheim;Pflaumheim;Schaafheim;;;;Babenhausen (Hess.);;Aschaffenburg ROB - Großostheim - Pflaumheim - Schaafheim - Babenhausen (Hess.)
27 | 55;Aschaffenburg ROB;;Großostheim;Mömlingen;;;;;Obernburg-Elsenfeld Bf.;;Aschaffenburg ROB - Großostheim - Mömlingen - Obernburg-Elsenfeld Bf.
28 | 56;Sulzbach am Main;Niedernberg;;;;;;;Großostheim;;Sulzbach am Main - Niedernberg - Großostheim
29 | 58;Aschaffenburg ROB;Mainaschaff;Zellhausen;Seligenstadt;;;;;Rodgau-Weiskirchen;;Aschaffenburg ROB - Mainaschaff - Zellhausen - Seligenstadt - Rodgau-Weiskirchen
30 | KEX 33;Schöllkrippen;;;;;;;;Aschaffenburg;Kahlgrundexpress;(Kahlgrundexpress) Schöllkrippen - Aschaffenburg
31 |
--------------------------------------------------------------------------------
/sources/linien_vab_kreis_mb.csv:
--------------------------------------------------------------------------------
1 | Linie;Start;über 1;über 2;über 3;über 4;über 5;Ziel;Laufweg
2 | 60;Aschaffenburg ROB;Niedernberg;Obernburg;;;;Obernburg-Elsenfeld Bf.;Aschaffenburg ROB - Niedernberg - Obernburg - Obernburg-Elsenfeld Bf.
3 | 61;Aschaffenburg ROB;Sulzbach;Kleinwallstadt;Obernburg-Elsenfeld Bf.;Erlenbach;Klingenberg;Mönchberg;Aschaffenburg ROB - Sulzbach - Kleinwallstadt - Obernburg-Elsenfeld Bf. - Erlenbach - Klingenberg - Mönchberg
4 | 62A;Roßbach;Volkersbrunn;;;;;Heimbuchenthal;Roßbach - Volkersbrunn - Heimbuchenthal
5 | 62;Aschaffenburg ROB;Leidersbach;Hausen;;;;Obernburg-Elsenfeld Bf.;Aschaffenburg ROB - Leidersbach - Hausen - Obernburg-Elsenfeld Bf.
6 | 63;Aschaffenburg ROB;Gailbach;Soden;Sulzbach;;;Dornau;Aschaffenburg ROB - Gailbach - Soden - Sulzbach - Dornau
7 | 64;Obernburg-Elsenfeld Bf.;Eschau;;;;;Neuhammer;Obernburg-Elsenfeld Bf. - Eschau - Neuhammer
8 | 65;Streit;Mechenhard;;;;;Erlenbach;Streit - Mechenhard - Erlenbach
9 | 67;Klingenberg;Wörth;Haingrund;;;;Seckmauern;Klingenberg - Wörth - Haingrund - Seckmauern
10 | 68;Obernburg-Elsenfeld Bf.;Obernburg;Eisenbach;;;;Mömlingen;Obernburg-Elsenfeld Bf. - Obernburg - Eisenbach - Mömlingen
11 | 69;Elsenfeld;Eichelsbach;Eschau;Streit;Rück;;Elsenfeld;Elsenfeld - Eichelsbach - Eschau - Streit - Rück - Elsenfeld
12 | 80;Miltenberg;Großheubach;Miltenberg;Bürgstadt;;;Miltenberg;Miltenberg - Großheubach - Miltenberg - Bürgstadt - Miltenberg
13 | 81;Miltenberg;Großheubach;Röllfeld;Klingenberg;;;Erlenbach Krankenhaus;Miltenberg - Großheubach - Röllfeld - Klingenberg - Erlenbach Krankenhaus
14 | 82;Miltenberg;Eichelbühl;;;;;Eichenbühl-Höhenorte;Miltenberg - Eichelbühl - Eichenbühl-Höhenorte
15 | 83;Miltenberg;Großheubach;Mönchberg;Eschau;Altenbuch;Stadtprozelten;Wertheim;Miltenberg - Großheubach - Mönchberg - Eschau - Altenbuch - Stadtprozelten - Wertheim
16 | 84;Miltenberg;Breitendiel;Mainbullau;Weilbach;;;Amorbach;Miltenberg - Breitendiel - Mainbullau - Weilbach - Amorbach
17 | 85;Miltenberg;Bürgstadt;Freudenberg;Stadtprozelten;;;Wertheim;Miltenberg - Bürgstadt - Freudenberg - Stadtprozelten - Wertheim
18 | 86;Miltenberg;Rüdenau;Kleinheubach;;;;Laudenbach;Miltenberg - Rüdenau - Kleinheubach - Laudenbach
19 | 87;Miltenberg;Wenschdorf;Monbrunn;Schippach;;;Berndiel;Miltenberg - Wenschdorf - Monbrunn - Schippach - Berndiel
20 | 88;Breitendiel;;;;;;Miltenberg;Breitendiel - Miltenberg
21 | 92;Amorbach;;;;;;Amorbach;Amorbach - Amorbach
22 | 93;Schneeberg;Kirchzell;Amorbach;Kleinheubach;;;Obernburg - Glanzstoffwerke;Schneeberg - Kirchzell - Amorbach - Kleinheubach - Obernburg - Glanzstoffwerke
23 | 94;Amorbach;Weilbach;Weckbach;;;;Gönz;Amorbach - Weilbach - Weckbach - Gönz
24 | 95;Amorbach;Kirchzell;Watterbach;Breitenbuch;;;Ottorfszell;Amorbach - Kirchzell - Watterbach - Breitenbuch - Ottorfszell
25 | 96;Amorbach;Buch;Preunschen;Mörschenhardt;;;Mudau;Amorbach - Buch - Preunschen - Mörschenhardt - Mudau
26 | 97;Gottersdorf;Reichartshausen;Neudorf;;;;Amorbach;Gottersdorf - Reichartshausen - Neudorf - Amorbach
27 | 98;Amorbach;Boxbrunn;;;;;Beuchen;Amorbach - Boxbrunn - Beuchen
28 | 99;Amorbach;Schneeberg;Hambrunn;;;;Zittenfelden;Amorbach - Schneeberg - Hambrunn - Zittenfelden
29 |
--------------------------------------------------------------------------------
/sources/linien_vab_stadt_ab.csv:
--------------------------------------------------------------------------------
1 | Linie;Start;über 1;über 2;über 3;Ziel;Laufweg
2 | 1;Aschaffenburg ROB;Obernau;;;Sulzbach;Aschaffenburg ROB - Obernau - Sulzbach
3 | 2;Aschaffenburg ROB;Dämmer Tor;;;Strietwald;Aschaffenburg ROB - Dämmer Tor - Strietwald
4 | 3;Aschaffenburg ROB;Leider;Waldfriedhof;;Stockstadt;Aschaffenburg ROB - Leider - Waldfriedhof - Stockstadt
5 | 4;Aschaffenburg ROB;;;;Schweinheim;Aschaffenburg ROB - Schweinheim
6 | 5;Aschaffenburg ROB;Gailbach;;;Dörrmorsbach;Aschaffenburg ROB - Gailbach - Dörrmorsbach
7 | 6;Aschaffenburg ROB;;;;Nilkheim;Aschaffenburg ROB - Nilkheim
8 | 7;Aschaffenburg ROB;Goldbach;Kugeldberg;;Unterafferbach;Aschaffenburg ROB - Goldbach - Kugeldberg - Unterafferbach
9 | 8;Aschaffenburg ROB;;;;Damm;Aschaffenburg ROB - Damm
10 | 9;Aschaffenburg ROB;;;;Glattbach;Aschaffenburg ROB - Glattbach
11 | 10;Aschaffenburg ROB;Schweinheim Blütenstraße;;;Schweinheim;Aschaffenburg ROB - Schweinheim Blütenstraße - Schweinheim
12 | 11;Aschaffenburg ROB;Dämmer Tor;;;Strietwald IHK;Aschaffenburg ROB - Dämmer Tor - Strietwald IHK
13 | 12;Aschaffenburg ROB;;;;Klinikum;Aschaffenburg ROB - Klinikum
14 | 14;Aschaffenburg ROB;;;;Mainaschaff;Aschaffenburg ROB - Mainaschaff
15 | 15;Aschaffenburg ROB;Bessenbacher Weg;;;Schweinheim;Aschaffenburg ROB - Bessenbacher Weg - Schweinheim
16 | 16;Aschaffenburg ROB;Klinikum;Haibach;Grünmorsbach;Dörrmorsbach;Aschaffenburg ROB - Klinikum - Haibach - Grünmorsbach - Dörrmorsbach
17 |
--------------------------------------------------------------------------------
/sources/linien_wtv.csv:
--------------------------------------------------------------------------------
1 | Linie;Laufweg
2 | 950;(Bonndorf -) Ewattingen - Wutach - Mundelfingen - Döggingen
3 | 7255;(Menzenschwand -) Seebrugg - Altglashütten < Bärental / Falkau > Titisee (- Neustadt)
4 | 7257;Seebrugg - Fischbach - Lenzkirch - Titisee - Neustadt
5 | 7258;Neustadt - Lenzkirch - Gündelwangen - Bonndorf
6 | 7259;SBG Wanderbus: Löffingen - Schattenmühle - Unadingen
7 | 7300;(Titisee - Feldberg -) Todtnau - Zell i. Wiesental (- Schopfheim)
8 | 7301;(Schwörstadt -) Rheinfelden - Wyhlen - Grenzach - Lörrach/- Basel Bad Bf
9 | 7313;Schopfheim - Schwörstadt
10 | 7317;Citybus Bad Säckingen Linie 1: Lohgerbe - Obersäckingen - Bremhag - Sonnenrain - Lohgerbe
11 | 3317;Citybus Bad Säckingen Linie 2: Lohgerbe - Kurgebiet - Lohgerbe
12 | 3217;Citybus Bad Säckingen Linie 3: Lohgerbe - Weststadt - Lohgerbe
13 | 7318;Waldshut - Dogern -/Unteralpfen - Birkingen - Buch - Albbruck
14 | 7319;St. Blasien - Häusern - Seebrugg
15 | 7320;Todtmoos - Wehr - Bad Säckingen
16 | 7321;St. Blasien - Menzenschwand - Bernau - St. Blasien/- Todtmoos
17 | 3321;Todtmoos - Herrenschwand - Präg - Todtnau
18 | 3221;St. Blasien - Ibach - Todtmoos
19 | 7322;Waldshut - Waldkirch - Höchenschwand - Häusern - St. Blasien
20 | 3322;Waldshut - Eschbach - Gaiss - Unteralpfen
21 | 3222;Höchenschwand - Attlisberg - Frohnschwand - Tiefenhäusern
22 | 7323;St. Blasien - Schlageten - Niedermühle
23 | 7324;St. Blasien - Ibach - Dachsberg - Rotzingen - Görwihl (- Albbruck - Waldshut)
24 | 3324;Görwihl - Niederwihl - Tiefenstein - Schachen - Albbruck (- Waldshut)
25 | 7325;StadtBus Laufenburg Linie 1: Ostbahnhof - Binzgen - Hochsal - Rotzel
26 | 3225;StadtBus Laufenburg Linie 2: Ostbahnhof - Grunholz - Luttingen - Stadenhausen - Ostbahnhof
27 | 7326;Bad Säckingen - Murg - Niederhof - Hänner (- Rickenbach)
28 | 7327;(Bad Säckingen -) Rickenbach - Görwihl - Herrischried - Rotzingen
29 | 7328;Bad Säckingen - Rickenbach - Herrischried - Todtmoos
30 | 7329;Wehr - Rickenbach - Hütten - Herrischried
31 | 7330;Laufenburg - Binzgen - Niederhof - Hänner
32 | 7331;(Waldshut -) Lauchringen - Griessen < Weisweil / Rechberg > Erzingen
33 | 7334;Waldshut - Albbruck - Laufenburg - Murg - Bad Säckingen
34 | 7335;Regiobus Bad Säckingen - Brennet - Wehr - Hasel - Schopfheim
35 | 3335;Brennet -/Hölzle - Enkendorf - Wehr - Zelg
36 | 7336;Waldshut Westring Busbahnhof - Krankenhaus - Liedermatte - Chilbiplatz - Busbahnhof
37 | 7337;Waldshut Nordring Busbahnhof - Chilbiplatz - Schmitzingen - Busbahnhof
38 | 7338;Waldshut - Lauchringen - Eggingen - Stühlingen - Fützen
39 | 7339;Waldshut Ostring Busbahnhof - Chilbiplatz - Aarberg - Busbahnhof
40 | 7340;Waldshut -/Tiengen - Kadelburg - Dangstetten - Reckingen - Hohentengen
41 | 3340;Lienheim - Bergöschingen - Hohentengen - Stetten
42 | 7341;Waldshut -/Tiengen - Gurtweil - Nöggenschwiel/- Indlekofen - Brunnardern
43 | 7342;Waldshut -/Tiengen - Gurtweil - (Berau -) Ühlingen - Grafenhausen - Seebrugg
44 | 3342;Ühlingen - Riedern am Wald (- Berau) -/Schönenbach - Buggenried - Mettenberg - Grafenhausen
45 | 3242;Waldshut -/Tiengen - Gurtweil - Berau - Brenden - Schönenbach
46 | 3142;Tiengen - Detzeln - Untermettingen - Ühlingen
47 | 7343;Bonndorf - Gündelwangen/- Grafenhausen - Seebrugg
48 | 7344;Bonndorf - Boll/- Lembach - Ewattingen (- Wutach Wutachmühle)
49 | 3344;Wanderbus Wutachschlucht: Holzschlag - Bonndorf - Schattenmühle - Bonndorf - Ewattingen - Wutach
50 | 7345;Waldshut - Tiengen - Detzeln - Untermettingen - Bettmaringen - Wellendingen - Bonndorf
51 | 3345;Tiengen - Detzeln - Aichen - Gurtweil - Tiengen
52 | 7346;Stühlingen - Weizen < Oberwangen / Dillendorf > Wellendingen - Bonndorf
53 | 3346;Stühlingen - Weizen - Grimmelshofen - Lausheim
54 | 3246;Stühlingen < Untere Alp / Eggingen > - < Bettmaringen / Wittlekofen > Bonndorf
55 | 7347;Erzingen - Grießen - Dettighofen - Jestetten
56 | 3347;Jestetten - Lottstetten - Nack
57 | 3247;Jestetten Altenburg - Jestetten
58 | 7348;Stadtverkehr Tiengen: Schulzentrum - Bahnhof - Mittlerer Berg - Stadtmitte - Schulzentrum
59 | 9051;FreizeitBus Menzenschwand - Äulemer Kreuz - Aha - Schluchsee
60 |
--------------------------------------------------------------------------------
/sources/orte_ch_add.csv:
--------------------------------------------------------------------------------
1 | Abk;Name
2 | DO2;Domodossola 2
3 | DOFM;Domodossola Güterumfahrung
4 | DOFS;Domodossola Personenbahnhof
5 | KODB;Konstanz DB
6 | LIFS;Luino
7 | LBT;Lötschberg Basistunnel
8 | NBS;Neubaustrecke (Bahn 2000)
9 |
--------------------------------------------------------------------------------
/sources/orte_de_add.csv:
--------------------------------------------------------------------------------
1 | Abk;Name
2 | XFRPV;Prény (Abzw)
3 | WPRAF;Prora Fundgrube/L29 (seit 2021/10 nicht mehr offizielle Abkürzung)
4 | FAOH;Frankfurt Abzweig Osthafen;Aus der Machbarkeitsstudie Fernbahntunnel Frankfurt
5 | FFTS;Frankfurt Hauptbahnhof Tief Süd;Aus der Machbarkeitsstudie Fernbahntunnel Frankfurt
6 | FHFG B;Hofgeismar Brücke
7 | FHFGB;Hofgeismar Bus
8 |
--------------------------------------------------------------------------------
/sources/orte_hamburg.csv:
--------------------------------------------------------------------------------
1 | Name;Abk
2 | Ahrensburg-Ost;AO
3 | Ahrensburg-West;AW
4 | Alsterdorf;AL
5 | Alter Teichweg;AT
6 | Barmbek;BA
7 | Baumwall;BL
8 | Beimoor;BM
9 | Berliner Tor;BT
10 | Berne;BE
11 | Billstedt;BI
12 | Borgweg;BO
13 | Brückenstraße;BK
14 | Buchenkamp;BP
15 | Buckhorn;BN
16 | Burgstraße;BG
17 | Christuskirche;CH
18 | Dehnhaide;DE
19 | Emilienstraße;EM
20 | Eppendorfer Baum;EP
21 | Farmsen;FA
22 | Feldstraße;FE
23 | Fuhlsbüttel;FU
24 | Fuhlsbüttel-Nord;FL
25 | Gänsemarkt;GM
26 | Garstedt;GA
27 | Großhansdorf;GH
28 | Habichtstraße;HA
29 | Hagenbecks Tierpark;HG
30 | Hagendeel;HL
31 | Hallerstraße;HR
32 | Hamburger Straße;HS
33 | Hammer Kirche;HK
34 | Hauptbahnhof-Nord;HX
35 | Hauptbahnhof-Süd;HB
36 | Hellkamp;HE
37 | Hoheluftbrücke;HO
38 | Hoisbüttel;HT
39 | Horner Rennbahn;HN
40 | Hudtwalckerstraße;HU
41 | Joachim-Mähl-Straße;JM
42 | Jungfernstieg;JG
43 | Kellinghusenstraße;KE
44 | Kiekut;KI
45 | Kiwittsmoor;KM
46 | Klein Borstel;KB
47 | Klosterstern;KR
48 | Landungsbrücken;LB
49 | Langenhorn-Markt;LM
50 | Langenhorn-Nord;LN
51 | Lattenkamp;LA
52 | Legienstraße;LE
53 | Lohmühlenstraße;LS
54 | Lübecker Straße;LU
55 | Lutterothstraße;LT
56 | Meiendorfer Weg;ME
57 | Merkenstraße;MS
58 | Meßberg;MB
59 | Messehallen;MH
60 | Mönckebergstraße;MO
61 | Mümmelmannsberg;MG
62 | Mundsburg;MU
63 | Niendorf-Markt;NM
64 | Niendorf-Nord;NN
65 | Norderstedt-Mitte;NO
66 | Ochsenzoll;OZ
67 | Ohlsdorf;OH
68 | Ohlstedt;OT
69 | Osterstraße;OS
70 | Rathaus;RA
71 | Rauhes Haus;RH
72 | Richtweg;RW
73 | Ritterstraße;RI
74 | Rödingsmarkt;RD
75 | Rothenburgsort;RO
76 | Saarlandstraße;SA
77 | Schippelsweg;SW
78 | Schlump;SL
79 | Schmalenbek;SK
80 | Sengelmannstraße;SE
81 | Sierichstraße;SI
82 | Spaldingstraße;SP
83 | St. Pauli;PA
84 | Steinfurther Allee;SF
85 | Steinstraße;ST
86 | Sternschanze;SZ
87 | Straßburger Straße;SR
88 | Süderstraße;SS
89 | Trabrennbahn;TR
90 | Uhlandstraße;UH
91 | Volksdorf;VF
92 | Wandsbeker Chaussee;WR
93 | Wandsbek-Gartenstadt;WK
94 | Wandsbek-Markt;WM
95 | Wartenau;WA
96 |
--------------------------------------------------------------------------------
/sources/orte_wien.csv:
--------------------------------------------------------------------------------
1 | Abk;Name
2 | AK;Aderklaaer Straße
3 | AS;Alser Straße
4 | AE;Alt Erlaa
5 | AD;Alte Donau
6 | PW;Am Schöpfwerk (U)
7 | AP;Aspern (U2)
8 | BA;Babenbergerstraße - Museumsquartier
9 | BR;Braunschweiggasse
10 | BE;Breitensee
11 | BS;Brünner Straße (in F)
12 | BM;Brunn-Maria Enzersdorf
13 | BU;Burggasse
14 | DJ;Donauinsel
15 | DP;Donauspital (U2)
16 | DT;Donaustadtbrücke (U2)
17 | DS;Dresdner Straße
18 | EK;Enkplatz
19 | ED;Erdberg
20 | ER;Erlaaer Straße
21 | FL;Floridsdorf (in F)
22 | FB;Friedensbrücke
23 | AW;Gasometer
24 | GE;Geiselbergstraße (in Sah)
25 | GH;Gersthof
26 | SM;Grillgasse (in Zur)
27 | GF;Großfeldsieldung
28 | GU;Gumpendorfer Straße
29 | GG;Gutheil-Schoder-Gasse
30 | HK;Handelskai
31 | HK;Handelskai (in Wv)
32 | AR;Hardegggasse (U2)
33 | HN;Hernals
34 | HZ;Herrengasse
35 | HI;Hietzing
36 | HH;Hütteldorfer Straße
37 | IP;Inzersdorf - Personenbahnhof
38 | JG;Jägerstraße
39 | J;Jedlersdorf (in F)
40 | JO;Johnstraße
41 | JS;Josefstädter Straße
42 | KT;Kagraner Platz
43 | KM;Kaisermühlen - Vienna International Centre
44 | KN;Kardinal-Nagl-Platz
45 | KP;Karlsplatz
46 | KR;Kendlerstraße
47 | KE;Keplerplatz
48 | KG;Kettenbrückengasse
49 | KL;Kledering (in Zur)
50 | KS;Klein Schwechat (in Kls)
51 | KI;Krieau
52 | KB;Krottenbachstraße
53 | LE;Längenfeldgasse
54 | LP;Leopoldau
55 | LU;Leopoldau U
56 | LG;Liesing (in Lg)
57 | LB;Lobau
58 | MG;Margaretengürtel
59 | MH;Meidling Hauptstraße
60 | MS;Messe
61 | MB;Michelbeuern, AKH
62 | NP;Nestroyplatz
63 | NE;Neu Erlaa
64 | MA;Neubaugasse - Mariahilfer Straße
65 | ND;Neue Donau
66 | NH;Niederhofstraße
67 | NF;Nußdorf
68 | NS;Nussdorfer Straße
69 | OV;Ober St. Veit
70 | OD;Oberdöbling
71 | OP;Oper (WLB)
72 | OK;Ottakring U
73 | PZ;Penzing
74 | PE;Perfektastraße
75 | PH;Philadelphiabrücke
76 | PG;Pilgramgasse
77 | SU;Praterkai
78 | PS;Purkersdorf Sanatorium
79 | RH;Rathaus
80 | RB;Rennbahnweg
81 | RW;Rennweg (in Nw)
82 | RP;Reumannplatz
83 | RG;Rochusgasse
84 | RL;Rossauer Lände
85 | SG;Schlachthausgasse
86 | SB;Schönbrunn
87 | LL;Schönbrunner Allee
88 | SK;Schöpfwerk (WLB)
89 | SR;Schottenring
90 | SO;Schottentor
91 | GS;Schwechat (in Kls)
92 | SP;Schwedenplatz
93 | SH;Schweglerstraße
94 | TH;Siebenhirten
95 | SI;Siemensstraße (in F)
96 | SA;Simmering (in El)
97 | AU;Spittelau (in Wf)
98 | SW;Stadion
99 | SD;Stadlau (in St)
100 | ST;Stadtpark
101 | SZ;Stephansplatz
102 | SE;Stubentor
103 | TB;Taborstraße
104 | TA;Taubstummengasse
105 | TS;Thaliastraße
106 | TG;Traisengasse
107 | TE;Tscherttegasse
108 | UV;Unter St. Veit
109 | MS;Vienna Biocenter-St.Marx
110 | VT;Volkstheater
111 | VS;Vorgartenstraße
112 | VD;Vösendorf - Siebenhirten
113 | WA;Währinger Straße, Volksoper
114 | AM;Wien Atzgersdorf (in Lg)
115 | KA;Wien Breitenleer Straße
116 | SV;Wien Erzherzog Karl-Straße (in St)
117 | WF;Wien Franz-Josefs-Bf (in Wf)
118 | WU;Wien Hadersdorf
119 | HD;Wien Haidestraße (in El)
120 | HU;Wien Hausfeldstraße
121 | HS;Wien Heiligenstadt
122 | HE;Wien Hetzendorf (in Mat)
123 | HA;Wien Hirschstetten (in St)
124 | HF;Wien Hütteldorf
125 | MP;Wien Matzleinsdorfer Platz (in Mat)
126 | MI;Wien Meidling (in Mat)
127 | LA;Wien Mitte (in Nw)
128 | PR;Wien Praterstern (in Nw)
129 | S;Wien Speising
130 | SS;Wien Strebersdorf (in F)
131 | WB;Wien Südbahnhof (in Wsp)
132 | WB;Wien Südbf (in Wbo)
133 | WB;Wien Südbf (in Wbo)
134 | SL;Wien Südtiroler Platz (in Wsp)
135 | SN;Wien Süßenbrunn (in Sue)
136 | WW;Wien Weidlingau
137 | WS;Wien Westbf (in Ws)
138 | WG;Wolfganggasse
139 | ZF;Zentralfriedhof
140 | GZ;Zieglergasse
141 | PP;Zippererstraße
142 |
--------------------------------------------------------------------------------
/sources/signale_bostrab.csv:
--------------------------------------------------------------------------------
1 | Abk;1976;1987;Bedeutung
2 | H0;;;Halt
3 | H1;;;Fahrt
4 | H2;;;Fahrt mit Geschwindigkeitsbeschränkung
5 | V0;;;Am folgenden Hauptsignal ist Halt zu erwarten
6 | V1;;;Am folgenden Hauptsignal ist Fahrt zu erwarten
7 | V2;;;Am folgenden Hauptsignal ist Fahrt mit Geschwindigkeitsbeschränkung zu erwarten
8 | F0;;;Halt
9 | F1;;;Fahrt freigegeben nur geradeaus
10 | F2;;;Fahrt freigegeben nur nach rechts
11 | F3;;;Fahrt freigegeben nur nach links
12 | F4;;;Halt zu erwarten
13 | F5;;;Fahrt freigegeben unter Beachtung der Abbiegeregeln nach §9 Straßenverkehrs-Ordnung
14 | A1;;;Türen schließen
15 | A2;;;Abfahren
16 | A2a;;;Abfahren (Optisch oder akustisch durch das Zugpersonal)
17 | A2b;;;Abfahren (Lichtsignal)
18 | Z1;;;Spitzensignal
19 | Z2;;;Schlusssignal
20 | Z3;;;Bremssignal
21 | Z4;;;Fahrtrichtungssignal
22 | Z5;;;Warnblinksignal
23 | G1;;;Ankündigung der Geschwindigkeitsbeschränkung. Zeigt Änderungen der zulässigen Geschwindigkeit nach unten an.
24 | G1a;;;Ankündigung der Geschwindigkeitsbeschränkung. Zeigt Änderungen der zulässigen Geschwindigkeit nach unten an. (Signaltafel)
25 | G1b;;;Ankündigung der Geschwindigkeitsbeschränkung. Zeigt Änderungen der zulässigen Geschwindigkeit nach unten an. (Lichtsignal)
26 | G2;;;Beginn der Geschwindigkeitsbeschränkung. Zeigt Änderungen der zulässigen Geschwindigkeit nach unten an.
27 | G2a;;;Beginn der Geschwindigkeitsbeschränkung. Zeigt Änderungen der zulässigen Geschwindigkeit nach unten an. (Signaltafel)
28 | G2b;;;Beginn der Geschwindigkeitsbeschränkung. Zeigt Änderungen der zulässigen Geschwindigkeit nach unten an. (Lichtsignal)
29 | G3;;;Ende der Geschwindigkeitsbeschränkung
30 | G4;;;Beginn der Geschwindigkeitsbegrenzung. Zeigt Änderungen der zulässigen Geschwindigkeit nach oben an.
31 | Sh1;;;Zwangshalt. Kennzeichnet Stellen, an denen bei Fahrt auf Sicht in jedem Fall anzuhalten ist.
32 | Sh2;;;Schutzhalt. Weiterfahrt ist unzulässig.
33 | Sh3;;;Nothalt
34 | Sh3a;;;Nothalt (akustisch)
35 | Sh3b;;;Nothalt (Kreissignal, Tagzeichen)
36 | Sh3c;;;Nothalt (Kreissignal, Nachtzeichen)
37 | Sh3d;;;Nothalt (Lichtsignal)
38 | Sh4;;;Läuten
39 | Sh5;;;Achtung
40 | Sh6;;;Grenzzeichen
41 | Sh7;;;Haltetafel
42 | R1;;;Wegfahren
43 | R2;;;Herkommen
44 | R3;;;Rangierhalt
45 | St1;;;Signalkontakt
46 | St2;;;Weichenkontakt
47 | St3;;;Ausschalten
48 | St4;;;Einschalten erlaubt
49 | St5;;;Stromabnehmer abziehen
50 | St6;;;Stromabnehmer anlegen
51 | St7;;;Streckentrenner. Der Fahrstrom ist kurz auszuschalten.
52 | St8;;;Halt für Fahrzeuge mit angelegtem Stromabnehmer
53 | W1;;;Weiche steht für Fahrt geradeaus mit höchstens 15 km/h
54 | W2;;;Weiche steht für Fahrt nach rechts mit höchstens 15 km/h
55 | W3;;;Weiche steht für Fahrt nach links mit höchstens 15 km/h
56 | W11;;;Weiche steht für Fahrt geradeaus mit zulässiger Geschwindigkeit
57 | W12;;;Weiche steht für Fahrt nach rechts mit zulässiger Geschwindigkeit
58 | W13;;;Weiche steht für Fahrt nach links mit zulässiger Geschwindigkeit
59 | W14;;;Weiche darf nicht aufgefahren werden
60 | Bü0;;;"Halt vor dem Bahnübergang; Weiterfahrt nur, wenn es die Verkehrslage erlaubt"
61 | Bü1;;;Der Bahnübergang darf befahren werden
62 | Bü2;;;Ein Überwachungssignal ist zu erwarten
63 | So1;;;Beginn einer Strecke mit Zugsicherung
64 | So2;;;Ende einer Strecke mit Zugsicherung
65 | So3;;;Standortkennzeichen. Gibt den Standort von Hauptsignalen an.
66 | So4;;;Auftragsschild. Gibt den Auftrag, am Signal H0 unter Beachtung besonderer Anordnungen, die in einer Dienstanweisung festgelegt sind, vorbeizufahren.
67 | So5;;;Begegnungsverbot – Anfang –
68 | So6;;;Begegnungsverbot – Ende –
69 |
--------------------------------------------------------------------------------
/sources/signale_no.csv:
--------------------------------------------------------------------------------
1 | Nummer;Betydning
2 | 1;Stopp
3 | 2;Varsom
4 | 3,3a;Innkjør
5 | 3b;Passér
6 | 4;Klar linje
7 | 5;Avgang
8 | 6;Tilsett bremsen
9 | 7;Løs bremsen
10 | 8;Kjør fram forbi middel
11 | 9;Kryssende tog er kommet
12 | 20,20a,20b;Stopp
13 | 21;Kjør (avvikelse over en eller flere sporveksler)
14 | 22;Kjør (uten avvikende togveksel)
15 | 23;Stopp (Forsignal)
16 | 24;Kjør (avvikelse over en eller flere sporveksler) (Forsignal)
17 | 25;Kjør (uten avvikende togveksel) (Forsignal)
18 | 31;Kjør (Hjelpesignal)
19 | 32;Vanskelig Togvei (Hjelpesignal)
20 | 34;Spornummersignal
21 | 35;Hovedlinjesignal
22 | 36;Togsportsignal
23 | 36a;Togsportsignal (fra avviketogspor)
24 | 36b;Togsportsignal (fra hovedtogspor)
25 | 37;Tillset bremsen
26 | 38;Løs bremsen
27 | 39;Avgang
28 | 41,43;Skifting forbudt
29 | 42,45;Skifting tillatt
30 | 44;Varsom skifting tillatt
31 | 46;Frigitt for lokal skifting
32 | 48;Stopp
33 | 49;Kjør fram
34 | 50;Bakk
35 | 51a;Rett fram
36 | 51b;Fra avvikespor
37 | 51c;Til venstre
38 | 51d;Til høyre
39 | 52a;Fra venstre til høyre
40 | 52b;Fra høyre til venstre
41 | 52c;Fra venstre til venstre
42 | 52d;Fra høyre til høyre
43 | 53;Sporet sperret
44 | 54;Sporet fritt
45 | 55;Stopp foran planovergangen
46 | 56;Planovergangen kan passeres
47 | 57;Planovergangsignalet viser "Stopp foran planovergangen"
48 | 58;Planovergangsignalet viser "Planovergangen kan passeres"
49 | 59;Rasfare
50 | 60;Tog kan passere rasfarestrekning
51 | 65a;Jordet seksjon
52 | 65b;Varslesignal for signal 65c og 65e
53 | 65c;Utkopling foran død seksjon
54 | 65d;Innkoppling etter død seksjon
55 | 65e;Senking av strømavtaker
56 | 65f;Heving av strømavtaker
57 | 65g;Stopp for elektrisk lokomotiv
58 | 66;Togvei slutt
59 | 67;Orienteringsignal
60 | 67a;Orienteringsignal
61 | 67b;Orienteringsignal for planovergang
62 | 67c;Orienteringsignal for holdeplass
63 | 67d;Orienteringsignal for planovergang og holdeplass
64 | 68;Hastighetssignaler
65 | 68a;Nedsatt kjørehastighet
66 | 68b;Økt kjørehastighet
67 | 68c;Avvikende nedsatt kjørehastighet
68 | 68d;Avvikende økt kjørehastighet
69 | 69;Midlertidig hastighetsignal
70 | 69a;Midlertidig kjørehastighet
71 | 69b;Midlertidig hastighet opphører
72 | 76;Stopp
73 | 78;Ingen avstigning
74 | 80;Gi akt og bemerket
75 | 81;Bremser på
76 | 82;Stopp
77 | 83;Tog kommer
78 | 84;Bremser av
79 | 85;Beredt
80 | 86;Alarm, faresignal
81 | 87;Kjøretillatelse mottatt
82 | 90;Forlamper
83 | 91;Baklamper
84 | 95;Sluttsignal
85 |
--------------------------------------------------------------------------------
/sources/strecken_de_alt.csv:
--------------------------------------------------------------------------------
1 | Tabellennummer;Liniennummer;Laufweg
2 | 136;RB 65 (neg);Niebüll - Dagebüll Mole
3 | 136 1,136¹;RB 66 (neg);Niebüll - Tønder (DK)
4 | 137;A 1 (AKN);Neumünster - Kaltenkrchen - Hamburg-Eidelstedt
5 | 138;A 2 (AKN);Ulzburg Süd - Norderstedt Mitte
6 | 139;A 3 (AKN);Elmshorn - Barmstedt - Ulzburg Süd
7 | 173;RB 16;Neustrelitz - Mirow
8 | 174;RB 19;Parchim - Karow (Meckl) - Plau am See
9 | 204;RE 4;Stendal - Berlin
10 | 209 46,209⁴⁶;RB 46;Cottbus - Forst (Lausitz)
11 | 209 51,209⁵¹;RB 51;Rathenow - Brandenburg
12 | 209 54,209⁵⁴;RB 54;Löwenberg (Mark) - Rheinsberg (Mark)
13 | 209 63,209⁶³;RB 63;Eberswalde - Joachimsthal - Templin Stadt
14 | 209 73,209⁷³;RB 73;Neustadt (Dosse) - Pritzwalk
15 | 209 74,209⁷⁴;RB 74;Pritzwalk - Meyenburg
16 | 220;RB 65;Cottbus - Görlitz - Zittau
17 | 229;RB 64;Görlitz - Hoyerswerda
18 | 236;L 7;Seifhennersdorf - Zittau
19 | 238;SOEG;Zittau - Kurort Oybin/Kurort Jonsdorf
20 | 269;RB 33;Stendal - Tangermünde
21 | 396;;Emden - Emden Außenhafen
22 | 479;RB 37;Boppard - Emmelshausen
23 | 514;RB 83 (FEG);Freiberg (Sachs) - Holzhau
24 | 691;RB 85;Bullay - Traben-Trarbach
25 |
--------------------------------------------------------------------------------
/sources/strecken_de_namen.csv:
--------------------------------------------------------------------------------
1 | Abk;Beschreibung;Nummer
2 | BBT;Brenner Basistunnel;
3 | GBT;Gotthard Basistunnel;
4 | KRM;SFS Köln-Rhein/Main;$2690
5 | LBT;Lötschberg Basistunnel;
6 | NBS;Neubaustrecke;
7 | SFS;Schnellfahrstrecke;
8 | VDE;Verkehrsprojekte Deutsche Einheit;
9 | VDE1;Lübeck/Hagenow Land-Rostock-Stralsund;
10 | VDE2;Berlin-Hamburg;$6100
11 | VDE3;Stendal-Uelzen;$6899
12 | VDE4;SFS Hannover-Berlin;$6107
13 | VDE5;Helmstedt-Magdeburg-Berlin;$6400
14 | VDE6;Halle-Hann. Münden;
15 | VDE7;Bebra-Erfurt;
16 | VDE8;Berlin-Nürnberg;
17 | VDE8¹,VDE8 1;Nürnberg-Erfurt;
18 | VDE8²,VDE8 2;Erfurt-Leipzig/Halle;
19 | VDE8³,VDE8 3;Leipzig/Halle-Berlin;
20 | VDE9;Leipzig-Dresden;
21 | 3669;Frankfurt Abzweig Osthafen - Frankfurt Mainkur (Fernbahntunnel Nordanbindung);Aus der Machbarkeitsstudie Fernbahntunnel Frankfurt
22 | FBTF;Fernbahntunnel Frankfurt
23 |
--------------------------------------------------------------------------------
/sources/strecken_ffm.csv:
--------------------------------------------------------------------------------
1 | Abk;Weg
2 | A;A-Strecke: Südbahnhof - Heddernheim - (Ginnheim/Bad Homburg/Oberursel)
3 | Aⅰ,AⅠ,AI;A-Strecke Teilabschnitt 1 Humser Straße - Hauptwache
4 | Aⅱ,AⅡ,AII;A-Strecke Teilabschnitt 2 Hauptwache - Willy-Brandt-Platz
5 | Aⅲ,AⅢ,AIII;A-Strecke Teilabschnitt 3 Humser Straße - Weißer Stein
6 | Aⅳ,AⅣ,AIV;A-Strecke Teilabschnitt 4 Willy-Brandt-Platz - Südbahnhof
7 | Aⅴ,AⅤ,AV;A-Strecke Teilabschnitt 5 Südbahnhof - Sachsenhäuser Warte (- Neu-Isenburg) (nicht weiterverfolgt)
8 | A1;Anschlussstrecke A1: Weißer Stein - Ginnheim
9 | A2;Anschlussstrecke A2: Heddernheim - Bad Homburg Gonzenheim
10 | A3;Anschlussstrecke A3: Abzweig Nordwest - Oberursel Hohemark
11 | B;B-Strecke: Europaviertel - Hauptbahnhof - Konstablerwache - (Preungesheim/Seckbacher Landstraße)
12 | Bⅰ,BⅠ,BI;B-Strecke Teilabschnitt 1: Scheffeleck - Willy-Brandt-Platz
13 | Bⅱ,BⅡ,BII;B-Strecke Teilabschnitt 2: Willy-Brandt-Platz - Hauptbahnhof
14 | Bⅳ,BⅣ,BIV;B-Strecke Teilabschnitt 4: Hauptbahnhof - Europaviertel (ursprünglich Nied - Höchst)
15 | B1;Anschlussstrecke B1: Scheffeleck - Preungesheim
16 | B2;Anschlussstrecke B2: Konstablerwache - Seckbacher Landstraße
17 | C;C-Strecke: (Praunheim/Hausen) - Industriehof - Zoo - (Ostbahnhof / Enkheim)
18 | Cⅰ,CⅠ,CI;C-Strecke Teilabschnitt 1: Alte Oper - Hauptwache
19 | Cⅱ,CⅡ,CII;C-Strecke Teilabschnitt 2: Hauptwache - Zoo
20 | Cⅲ,CⅢ,CIII;C-Strecke Teilabschnitt 3: Bockenheimer Warte - Alte Oper
21 | Cⅳ,CⅣ,CIV;C-Strecke Teilabschnitt 4: Zoo - Ostbahnhof
22 | Cⅴ,CⅤ,CV;C-Strecke Teilabschnitt 5: Industriehof - Bockenheimer Warte
23 | C1;Anschlussstrecke C1: Zoo - Eissporhalle - Enkheim
24 | D;D-Strecke: (Schwanheim / Stadion) - Hauptbahnhof - Ginnheim - Kalbach
25 | Dⅰ,DⅠ,DI;D-Strecke Teilabschnitt 1: Hauptbahnhof - Bockenheimer Warte
26 | Dⅱ,DⅡ,DII;D-Strecke Teilabschnitt 2: Bockenheimer Warte - Ginnheim (geplant)
27 | Dⅲ,DⅢ,DIII;D-Strecke Teilabschnitt 3: Niederrad - Hauptbahnhof (nicht weiterverfolgt)
28 | Dⅳ,DⅣ,DIV;D-Strecke Teilabschnitt 4: Nordweststadt - Riedberg - Kalbach
29 |
--------------------------------------------------------------------------------
/sources/strecken_no.csv:
--------------------------------------------------------------------------------
1 | Blad;Vei
2 | 1;(Skøyen - Oslo S -) Lillestrøm - Årnes - Skarnes - Kongsvinger - Charlottenberg (- Arvika)
3 | 2;Kongsvinger - Elverum
4 | 3;Skøyen - Oslo S - Loenga - Kolbotn - Ski - Moss - Fredrikstad - Sarpsborg - Halden - Kornsjø (- Ed)
5 | 4;(Skøyen - Oslo S - Kolbotn Ski -) Mysen - Sarpsborg
6 | 5;Gjøvikbanen: (Skøyen -) Oslo S - Grefsen - Hakadal - Roa - Jaren - Eina - Gjøvik
7 | 6;Flåmsbana: Myrdal - Flåm
8 | 7;Bergensbanen: Hønefoss - Ål - Myrdal - Voss - Bergen
9 | 8;Drammenbanen: Oslo S - Skøyen - Lysaker - Sandvika - Asker - Drammen
10 | 8b;Lysaker - Sandvika - Asker - Spikkestad
11 | 8c;Filipstad - Skøyen
12 | 9;Hovedbanen: Skøyen - Oslo S - Grorud - Lillestrøm - Eidsvoll
13 | 9b;Grorud - Alnabru
14 | 9c;Aker - Alnabru
15 | 9d;Alnabru - Brobekk
16 | 9e;Alnabru - Loenga
17 | 10;Eidsvoll - Hamar - Lillehammer - Ringebu - Otta - Dombås
18 | 11;Trondheim S - Trondheim M - Støren - Oppdal - Dombås
19 | 12;Raumabana: Åndalsnes - Dombås
20 | 13;Rørosbana: Støren - Røros - Tynset - Koppang - Elverum - Hamar
21 | 14;Grong - Steinkjer - Levanger - Stjørdal - Hell - Trondheim S
22 | 14b;Leangen - Trondheim M
23 | 14c;Meråkerbanen: Hell - Storlien
24 | 15;Nordlandsbanen: Bodø - Fauske - Mo i Rana - Mosjøen - Grong
25 | 16;Ofotbanen; Narvik - Bjørnfjell - Vassijaure
26 | 17;Drammen - Hokksund - Kongsberg - Hjuksebø - Nordagutu - Neslandsvatn
27 | 18;Nordagutu - Neslandsvatn - Nelaug - Kristiansand
28 | 19;Kristiansand - Sira - Egersund - Vigrestad - Bryne - Sandnes - Stavanger
29 | 20;Hokksund - Hønefoss
30 | 21;Drammen - Tønsberg - Sandefjord - Larvik - Porsgrunn - Skien - Nordagutu
31 | 21b;Tinnoset - Notodden - Hjuksebø
32 | 21c;Myrane - Ørvik - Brevik s.sp
33 | 22;Arendal - Nelaug
34 | 99;Gardermobanen: Eisdvoll - Gardermoen - Lillestrøm - Oslo S
35 |
--------------------------------------------------------------------------------
/statistics:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | '''Helper for tooting bot statistics'''
4 |
5 | import argparse
6 | import configparser
7 | import datetime
8 | import logging
9 | from Externals import setup_database, set_arguments, setup_network, test_network_arguments
10 | import Persistence
11 |
12 | logger = Persistence.init_logger('statistics')
13 |
14 | one_day = datetime.timedelta(days=1)
15 | today = datetime.date.today()
16 | first = today.replace(day=1)
17 | january_first = first.replace(month=1)
18 |
19 | parser = argparse.ArgumentParser(description=__doc__)
20 | set_arguments(parser)
21 | Persistence.set_logging_args(parser, 'INFO')
22 | parser.add_argument('--since',
23 | dest='since',
24 | help='Time frame for statistics',
25 | required=False,
26 | choices=['0', 'month', 'year'],
27 | default=0)
28 | args = parser.parse_args()
29 | configuration = configparser.ConfigParser()
30 | configuration.read(args.config)
31 | args.config = configuration
32 | network = test_network_arguments(args)
33 | logger.setLevel(getattr(logging, args.log_level))
34 | logger.debug("statistics running args: %s", args)
35 |
36 | if args.since == "0":
37 | since = 0
38 | since_text = 'Beginn'
39 | elif args.since == 'month':
40 | since = (first - one_day).strftime("%Y%m01")
41 | since_text = 'Anfang letzten Monats'
42 | elif args.since == 'year':
43 | since = (january_first - one_day).strftime("%Y0101")
44 | since_text = 'Anfang letzten Jahres'
45 |
46 | sql = setup_database(args, network)
47 |
48 | counts = sql.count_status(since=since)
49 | text = f"""Zeit für Statistik! Daten für die Zeit seit {since_text}. Ich habe:
50 | • {counts.get('found', 0)} Kürzel beantwortet, für
51 | • {counts.get('notfound', 0)} Kürzel keine lange Version erkannt und
52 | • {counts.get('blacklist', 0)} nicht beantwortet, weil sie auf der Blacklist standen.
53 |
54 | Die populärsten Kürzel waren:
55 | """
56 |
57 | for row in sql.popular_abbrs(since):
58 | text += f"• {row['S']} ({row['C']}×)\n\u200b"
59 | text += """
60 | Die populärsten Quellen waren:
61 | """
62 | for row in sql.popular_sources(since):
63 | text += f"• {row['S']} ({row['C']}×)\n\u200b"
64 | text += """
65 | (Keine Garantie für richtiges Zählen)"""
66 |
67 | print(text.replace("\u200b", ""))
68 |
69 | if args.readwrite:
70 | nw_api = setup_network(network, args, {})
71 | nw_api.post(text)
72 | else:
73 | logger.info("Readonly: not really sending that status.")
74 |
--------------------------------------------------------------------------------
/test:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | """Tester for the bot"""
4 |
5 | import argparse
6 | import logging
7 |
8 | from AnswerMachine import handle_list
9 | from Externals import setup_database
10 | import Mock
11 |
12 | import Persistence
13 |
14 | logger = Persistence.init_logger('bot')
15 |
16 | def arguments():
17 | parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
18 | description=__doc__,
19 | epilog="""Possible sources:
20 | testcases: Use the list of all mocked testcase tweets
21 | id: Out of the list of all mocked testcase tweets, use only the ones given with the --id
22 | attribute
23 | external: Use mocked tweet objects from tweet_details.py. That file may be created with
24 | get_tweet.
25 | """)
26 | Persistence.set_logging_args(parser)
27 | parser.add_argument('--source',
28 | choices=['testcases', 'id', 'external'],
29 | default='testcases',
30 | help='''Specify source of testable tweets. See possible values below''',
31 | required=False,
32 | )
33 | parser.add_argument('--id',
34 | required=False,
35 | nargs='*',
36 | help='''The ids of test tweets to look at. Only valid with --source id'''
37 | )
38 | parser.add_argument('--output',
39 | choices=['summary', 'descriptive'],
40 | default='descriptive',
41 | help='Kind of statistics output: One-line-summary or a little more verbose.'
42 | )
43 | parser.add_argument('--readwrite', default=False, help='Will be forced to be false')
44 | args_ = parser.parse_args()
45 | args_.readwrite = False
46 | if args_.source == 'id' and args_.id is None:
47 | parser.print_help()
48 | parser.exit("Error: --source id given, but no --id found")
49 | if args_.source != 'id' and args_.id is not None:
50 | parser.print_help()
51 | parser.exit("Error: --id given, but --source is not 'id'")
52 | logger.setLevel(getattr(logging, args_.log_level.upper()))
53 | logging.getLogger('msg').setLevel(logging.CRITICAL)
54 | logger.debug("test running args: %s", args_)
55 | return args_
56 |
57 | if __name__ == "__main__":
58 | try:
59 | args = arguments()
60 | id_list = args.id if args.id is not None else []
61 | database = setup_database(args, 'twitter')
62 | logger.info("Trying to create mock api from %s", args.source)
63 | twitter = Mock.MockApi(mode=args.source,
64 | id_list=[int(x) for x in id_list])
65 |
66 | magic_tags, magic_emojis = database.magic_hashtags()
67 | handle_list(network=twitter,
68 | database=database,
69 | magic_tags=magic_tags,
70 | magic_emojis=magic_emojis)
71 | if args.source != 'external':
72 | raise SystemExit(twitter.statistics(args.output))
73 | except Exception as e: # pylint: disable=W0703
74 | logger.log(51, "TESTS FAIL TO RUN")
75 | logger.exception("%s", e)
76 |
--------------------------------------------------------------------------------
/tests/test_network.py:
--------------------------------------------------------------------------------
1 | """Unit tests for AnswerMachine.react.process_commands"""
2 |
3 | import logging
4 |
5 | from Externals.message import Message
6 | from Externals.network import Network
7 | from AnswerMachine.react import process_commands
8 |
9 | log = logging.getLogger('test')
10 |
11 | class MockApi(Network): # pylint: disable=abstract-method
12 | def __init__(self, willfollow, willdefollow):
13 | self.willdefollow = willdefollow
14 | self.willfollow = willfollow
15 |
16 | def is_followed(self, author):
17 | log.critical(author)
18 | return author == "follows"
19 |
20 | def follow(self, _):
21 | assert self.willfollow
22 |
23 | def defollow(self, _):
24 | assert self.willdefollow
25 |
26 | def test_folgenbitte_not_following():
27 | msg = Message(id=0, text="blabla", author="followsnot", hashtag_texts=['folgenbitte'])
28 | process_commands(msg, MockApi(True, False))
29 |
30 | def test_folgenbitte_following():
31 | msg = Message(id=0, text="blabla", author="follows", hashtag_texts=['folgenbitte'])
32 | process_commands(msg, MockApi(False, False))
33 |
34 | def test_entfolgen_not_following():
35 | msg = Message(id=0, text="blabla", author="followsnot", hashtag_texts=['entfolgen'])
36 | process_commands(msg, MockApi(False, False))
37 |
38 | def test_entfolgen_following():
39 | msg = Message(id=0, text="blabla", author="follows", hashtag_texts=['entfolgen'])
40 | process_commands(msg, MockApi(False, True))
41 |
42 | def test_both_following():
43 | msg = Message(id=0, text="blabla", author="follows",
44 | hashtag_texts=['folgenbitte', 'entfolgen'])
45 | process_commands(msg, MockApi(False, True))
46 |
47 | def test_both_not_following():
48 | msg = Message(id=0, text="blabla", author="followsnot",
49 | hashtag_texts=['entfolgen', 'folgenbitte'])
50 | process_commands(msg, MockApi(True, True))
51 |
--------------------------------------------------------------------------------
/tests/test_process_commands.py:
--------------------------------------------------------------------------------
1 | """Unit tests for AnswerMachine.react.process_commands"""
2 |
3 | from Externals.message import Message
4 | from AnswerMachine.react import process_commands
5 |
6 | class MockApi:
7 | def __init__(self, willask, willdeask):
8 | self.will_ask = willask
9 | self.will_deask = willdeask
10 |
11 | def handle_followrequest(self, _):
12 | assert self.will_ask
13 |
14 | def handle_defollowrequest(self, _):
15 | assert self.will_deask
16 |
17 | def test_nocommand():
18 | msg = Message(id=0, text="blabla", author=None, hashtag_texts=[])
19 | try:
20 | process_commands(msg, None)
21 | except AttributeError:
22 | assert False, "unprocessable Message needs API"
23 |
24 | def test_folgenbitte_not_following():
25 | msg = Message(id=0, text="blabla", author="followsnot", hashtag_texts=['folgenbitte'])
26 | process_commands(msg, MockApi(True, False))
27 |
28 | def test_folgenbitte_following():
29 | msg = Message(id=0, text="blabla", author="follows", hashtag_texts=['folgenbitte'])
30 | process_commands(msg, MockApi(True, False))
31 |
32 | def test_entfolgen_not_following():
33 | msg = Message(id=0, text="blabla", author="followsnot", hashtag_texts=['entfolgen'])
34 | process_commands(msg, MockApi(False, True))
35 |
36 | def test_entfolgen_following():
37 | msg = Message(id=0, text="blabla", author="follows", hashtag_texts=['entfolgen'])
38 | process_commands(msg, MockApi(False, True))
39 |
40 | def test_both_following():
41 | msg = Message(id=0, text="blabla", author="follows",
42 | hashtag_texts=['folgenbitte', 'entfolgen'])
43 | process_commands(msg, MockApi(True, True))
44 |
45 | def test_both_not_following():
46 | msg = Message(id=0, text="blabla", author="followsnot",
47 | hashtag_texts=['entfolgen', 'folgenbitte'])
48 | process_commands(msg, MockApi(True, True))
49 |
--------------------------------------------------------------------------------
/tests/test_process_magic.py:
--------------------------------------------------------------------------------
1 | """Unit tests for AnswerMachine.react.process_magic"""
2 |
3 | from AnswerMachine.react import process_magic
4 |
5 | def test_empty():
6 | assert process_magic([], 13, 'DEFAULT') == [['DEFAULT', [0, 0]], ['__', [13, 13]]]
7 |
8 | def test_movetostart():
9 | inp = [
10 | ['ASDF', [3, 6]],
11 | ]
12 | out = [*inp, ['__', [15, 15]]]
13 | assert process_magic(inp, 15, 'D') == out
14 |
15 | def test_keeporder():
16 | inp = [
17 | ['ASDF', [0, 6]],
18 | ['DDDD', [9, 6]],
19 | ['ASDF', [0, 5]],
20 | ['AAAA', [0, 8]],
21 | ['ERTF', [4, 2]],
22 | ]
23 | out = [*inp, ['__', [20, 20]]]
24 | assert process_magic(inp, 20, 'D') == out
25 |
--------------------------------------------------------------------------------
/tools/add_score_to_commit_msg:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | pylint_score=$(\
4 | tools/check | \
5 | grep has\ been\ rated | \
6 | grep -o '[0-9]\+\.[0-9][0-9]' | \
7 | head -n 1 \
8 | )
9 | test_result=$(./test --source testcases --output summary --log-level CRITICAL 2>&1)
10 | pytest_result=$(python3 -m pytest tests/ --disable-warnings -q | head -n 1 | tr -s ' ')
11 |
12 | echo "Adding pylint score $pylint_score..."
13 | echo "...and test result $test_result..."
14 | echo "...and pytest result $pytest_result..."
15 | echo "...to commit message:"
16 |
17 | git commit --allow-empty --amend -m "$(git log --format=%B -n1 | grep -v pylint\ score | grep -v test\ score | grep -v pytest\ score)
18 |
19 | pylint score: $pylint_score
20 | test score: $test_result
21 | pytest score: $pytest_result"
22 |
23 | git log --format=%B -n1
24 |
--------------------------------------------------------------------------------
/tools/check:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | pylint \
4 | --reports=n \
5 | $(tools/find_all_pys)
6 |
--------------------------------------------------------------------------------
/tools/find_all_pys:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | git ls-files | grep py$;
4 | grep -RIl '^../usr/bin/python3' | grep -v \.py$
5 |
--------------------------------------------------------------------------------
/tools/manage-blacklist:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | """Helper program for management of the bot blacklist"""
4 |
5 | import argparse
6 | from sys import stderr
7 | import parentdir # pylint: disable=W0611
8 | from Externals import setup_database
9 |
10 | parser = argparse.ArgumentParser(description=__doc__)
11 | parser.add_argument('--list', action='store_true', required=False, default=False)
12 | parser.add_argument('--add', action='store', required=False)
13 | # parser.add_argument('--remove', action='store', required=False)
14 | parser.add_argument('--statistics-for', action='store', required=False)
15 | parser.add_argument('--readwrite', help='Change Database', required=False, default=True)
16 | args = parser.parse_args()
17 |
18 | sql = setup_database(args, None)
19 |
20 | if args.list:
21 | sql.cursor.execute("""
22 | SELECT
23 | source,
24 | Abk
25 | FROM
26 | blacklist
27 | """)
28 | for row in sql.cursor.fetchall():
29 | print(row['source'], row['Abk'])
30 | raise SystemExit(0)
31 | if not args.statistics_for is None:
32 | print("Statistics for", args.statistics_for)
33 | sql.cursor.execute("""
34 | SELECT
35 | count(status) as c,
36 | status
37 | FROM
38 | requestlog
39 | WHERE
40 | abbreviation LIKE ?
41 | GROUP BY
42 | status
43 | """, (args.statistics_for, ))
44 | tot_sum = 0
45 | for row in sql.cursor.fetchall():
46 | tot_sum += row['c']
47 | print(row['c'], row['status'])
48 | print(tot_sum, "total")
49 | raise SystemExit(0)
50 | if not args.add is None:
51 | sql.cursor.execute("""
52 | SELECT
53 | 1
54 | FROM
55 | blacklist
56 | WHERE
57 | source || ':' || Abk = ?
58 | """, (args.add, ))
59 | row = sql.cursor.fetchone()
60 | if row is None:
61 | parts = args.add.split(':')
62 | sql.cursor.execute("""
63 | INSERT INTO
64 | blacklist(source, Abk)
65 | VALUES(?, ?)
66 | """, (parts[0], parts[1],))
67 | if sql.cursor.rowcount == 0:
68 | print("Keine Daten eingetragen", file=stderr)
69 | raise SystemExit(1)
70 | print("Erfolgreich eingetragen!")
71 | sql.close_sucessfully()
72 | raise SystemExit(0)
73 | print("Schon eingetragen!")
74 | raise SystemExit(0)
75 |
--------------------------------------------------------------------------------
/tools/parentdir.py:
--------------------------------------------------------------------------------
1 | """Add parent directory to sys.path for module importing"""
2 |
3 | import sys
4 | from pathlib import Path
5 | sys.path.append(str(Path(__file__).resolve().parents[1]))
6 |
--------------------------------------------------------------------------------
/tools/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | """Setup of data and documentation"""
4 |
5 | import argparse
6 | import logging
7 | from pathlib import Path
8 | import subprocess
9 | import parentdir # pylint: disable=W0611
10 | import Documentation
11 | from Externals import setup_database
12 | from GitVersion import Git
13 | from Import import find_all_configs
14 | import Persistence
15 |
16 | logger = Persistence.init_logger('setup')
17 |
18 | parser = argparse.ArgumentParser(description=__doc__)
19 | Persistence.set_logging_args(parser, 'INFO')
20 | parser.add_argument('--readwrite',
21 | help='Actually do stuff',
22 | required=False,
23 | default=True)
24 | args = parser.parse_args()
25 |
26 | logger.setLevel(getattr(logging, args.log_level.upper()))
27 | logger.debug("setup running args: %s", args)
28 |
29 | output_dir = Path('output')
30 | dump_dir = output_dir / 'dumps'
31 | config_dir = Path('data')
32 | doc_source = Path('doc')
33 | cardsource = Path('cards')
34 | Path.mkdir(dump_dir, parents=True, exist_ok=True)
35 |
36 | database = setup_database(args, None)
37 | database.purge_data()
38 |
39 | configurations = find_all_configs(config_dir)
40 | if configurations is None:
41 | raise SystemExit(1)
42 | navilinks = Documentation.navilink_list(Git().describe('--dirty'))
43 | dumplinks = Documentation.dumplink_list(configurations)
44 |
45 | Documentation.create_documentation(navilinks, doc_source, output_dir)
46 | Documentation.create_dump_mainpage(navilinks, dumplinks, dump_dir)
47 | dRM = Documentation.MarkdownDoc(Path("data") / 'README.md', navilinks)
48 | dRM.write(output_dir / 'data.html')
49 | sRM = Documentation.MarkdownDoc(Path("sources") / 'README.md', navilinks)
50 | sRM.write(output_dir / 'sources.html')
51 |
52 | licpage = Documentation.Licenses(doc_source / 'copyright.md', navilinks)
53 |
54 | for cid, config in sorted(configurations.items()):
55 | logger.info("Processing file %s", cid)
56 | is_default = True
57 | for a in config.access:
58 | database.insert_source(a, cid, is_default)
59 | is_default = False # only first one.
60 | for mht in config.magic_hashtags:
61 | database.insert_magic_hashtag(cid, mht)
62 | for dl in config.data_list:
63 | if not database.insert_datalist(dl, cid):
64 | raise SystemExit(1)
65 | Documentation.dump_source(config, dumplinks, navilinks, database, dump_dir)
66 | licpage.add_source(config)
67 |
68 | licpage.write(output_dir / 'copyright.html')
69 | Documentation.dump_ignorelist(dumplinks, navilinks, database, dump_dir)
70 | database.close_sucessfully()
71 |
72 | subprocess.run(['chmod', '-R', 'ug=rwX,o=rX', str(output_dir)], check=False)
73 | target_dir = Path('/var/www/ds100/')
74 | avatar_dir = Path('/var/www/avatar/')
75 | if target_dir.exists():
76 | subprocess.run(['rsync', '-a', str(output_dir) + "/", str(target_dir)], check=False)
77 | for fn in ('bot.css', 'mastodon-icon.png', 'twitter-icon.png', 'script.js'):
78 | subprocess.run(['rsync', '-a', str(doc_source / fn), str(target_dir)], check=False)
79 | subprocess.run(['rsync', '-a', str(cardsource / 'socialcard.png'), str(target_dir)],
80 | check=False)
81 | else:
82 | logger.warning('Not copying documentation')
83 | if avatar_dir.exists():
84 | subprocess.run(['rsync', '-a', str(doc_source / 'avatar.svg'), str(avatar_dir / 'ds100.svg')],
85 | check=False)
86 | subprocess.run(['rsync', '-a', str(doc_source / 'avatar-ril100.svg'), str(avatar_dir /
87 | 'ril100.svg')], check=False)
88 | else:
89 | logger.warning('Not copying avatar')
90 |
91 | logger.info("Done")
92 |
--------------------------------------------------------------------------------