Skip to content

Commit d1d52e3

Browse files
committed
Initial commit
0 parents  commit d1d52e3

File tree

8 files changed

+1154
-0
lines changed

8 files changed

+1154
-0
lines changed

.github/FUNDING.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
github: [DenverCoder1]
2+
patreon:
3+
open_collective:
4+
ko_fi:
5+
tidelift:
6+
community_bridge:
7+
liberapay:
8+
issuehunt:
9+
otechie:
10+
custom:

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__pycache__
2+
3+
.vscode

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Jonah Lawrence
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# timezone-convert-albert-ext
2+
3+
[![discord](https://custom-icon-badges.herokuapp.com/discord/819650821314052106?color=5865F2&logo=discord-outline&logoColor=white "Dev Pro Tips Discussion & Support Server")](https://discord.gg/fPrdqh3Zfu)
4+
[![License MIT](https://custom-icon-badges.herokuapp.com/github/license/DenverCoder1/timezone-convert-albert-ext.svg?logo=repo)](https://github.com/DenverCoder1/timezone-convert-albert-ext/blob/main/LICENSE)
5+
[![code style black](https://custom-icon-badges.herokuapp.com/badge/code%20style-black-black.svg?logo=black-b&logoColor=white)](https://github.com/psf/black)
6+
7+
Extension for converting between timezones in [Albert launcher](https://albertlauncher.github.io/)
8+
9+
![image](https://user-images.githubusercontent.com/20955511/142168605-4e4badca-5693-4c4f-8f20-f03b8723c97f.png)
10+
11+
## Installation
12+
13+
1. Locate the `modules` directory in the Python extension data directory.
14+
15+
The data directories reside in the data directories of the application defined by Qt. Hence on linux the modules would be looked up in the following directories (in this order):
16+
17+
```
18+
~/.local/share/albert/org.albert.extension.python/modules
19+
/usr/local/share/albert/org.albert.extension.python/modules
20+
/usr/share/albert/org.albert.extension.python/modules
21+
```
22+
23+
Double-clicking on a module in the settings will open the directory in the file manager.
24+
25+
2. Clone this repository into your `modules` directory.
26+
27+
```bash
28+
cd /path/to/modules
29+
30+
git clone https://github.com/DenverCoder1/timezone-convert-albert-ext.git
31+
```
32+
33+
3. Install `dateparser` using pip.
34+
35+
```bash
36+
python3 -m pip install dateparser
37+
```
38+
39+
4. Enable the extension in the settings.
40+
41+
![settings](https://user-images.githubusercontent.com/20955511/142149401-188a865a-211e-4aa9-9e03-bf6314c2041e.png)
42+
43+
## Usage
44+
45+
Type a time, followed by the word "to" or "in" and then the timezone you want to convert to.
46+
47+
Examples:
48+
49+
`10pm PST to CST`
50+
51+
`8am MST in New York`
52+
53+
## Config
54+
55+
In `config.py` there are options to customize the extension:
56+
57+
### 24-hour time
58+
59+
To enable 24-hour time, set `hr24` to `True`.
60+
61+
### Timezone aliases
62+
63+
To add a city or abbreviation as an alias for a timezone, add it to `aliases` as a key-value pair.
64+
65+
66+
67+
## Contributing
68+
69+
If you have any questions, suggestions, or issues, please feel free to open an issue or pull request.
70+
71+
## Support
72+
73+
💙 If you like this project, give it a ⭐ and share it with friends!
74+
75+
<p align="left">
76+
<a href="https://www.youtube.com/channel/UCipSxT7a3rn81vGLw9lqRkg?sub_confirmation=1"><img alt="Youtube" title="Youtube" src="https://custom-icon-badges.herokuapp.com/badge/-Subscribe-red?style=for-the-badge&logo=video&logoColor=white"/></a>
77+
<a href="https://github.com/sponsors/DenverCoder1"><img alt="Sponsor with Github" title="Sponsor with Github" src="https://custom-icon-badges.herokuapp.com/badge/-Sponsor-ea4aaa?style=for-the-badge&logo=heart&logoColor=white"/></a>
78+
</p>
79+
80+
[☕ Buy me a coffee](https://ko-fi.com/jlawrence)

__init__.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import datetime
4+
import re
5+
import traceback
6+
from pathlib import Path
7+
from typing import List
8+
9+
import albert
10+
11+
from dates import format_date, parse_date
12+
13+
__doc__ = """
14+
Extension for converting between timezones
15+
16+
Synopsis: `<from_time> [to|in] <to_tz>`
17+
18+
Examples:
19+
`10pm PST to CST`
20+
`8am MST in New York`
21+
22+
24-hour time and timezone aliases can be set in config.py
23+
"""
24+
__title__ = "Timezone Convert"
25+
__version__ = "0.0.1"
26+
__authors__ = "Jonah Lawrence"
27+
__py_deps__ = ["dateparser"]
28+
29+
local_timezone = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo
30+
31+
timezone_regex = re.compile(
32+
r"(?P<from_time>.*(?:pm|am|\d:\d).*)\s(?P<seperator>to|in)\s(?P<to_tz>.*)", re.I
33+
)
34+
35+
36+
def get_icon_path() -> str:
37+
"""
38+
Get the path to the icon
39+
40+
Returns:
41+
str: The path to the icon.
42+
"""
43+
return str(Path(__file__).parent / "icons" / "clock.svg")
44+
45+
46+
def get_item(text: str, subtext: str) -> albert.Item:
47+
"""
48+
Create an albert.Item from a text and subtext.
49+
50+
Args:
51+
text (str): The text to display.
52+
subtext (str): The subtext to display.
53+
54+
Returns:
55+
albert.Item: The item to be added to the list of results.
56+
"""
57+
return albert.Item(
58+
id=__title__,
59+
icon=get_icon_path(),
60+
text=text,
61+
subtext=subtext,
62+
actions=[albert.ClipAction("Copy result to clipboard", text)],
63+
)
64+
65+
66+
def get_items(from_time: str, to_tz: str) -> List[albert.Item]:
67+
"""
68+
Generate the Albert items to display for the query.
69+
70+
Args:
71+
query_string (str): The query string to be parsed.
72+
73+
Returns:
74+
List[albert.Item]: The list of items to display.
75+
"""
76+
# parse from_time by itself
77+
from_dt = parse_date(from_time)
78+
if not from_dt:
79+
return [get_item(f"Error: Could not parse date: {from_time}", "")]
80+
# parse time with target timezone
81+
result_dt = parse_date(from_time, to_tz=to_tz)
82+
if not result_dt:
83+
return [get_item(f"Error: Could not parse timezone: {to_tz}", "")]
84+
# format the results
85+
from_str = format_date(from_dt)
86+
result_str = format_date(result_dt)
87+
from_tz = from_dt.tzname() or local_timezone.tzname(from_dt) or ""
88+
result_tz = result_dt.tzname() or ""
89+
return [
90+
get_item(
91+
f"{result_str} {result_tz}",
92+
f"Converted from {from_str} {from_tz}",
93+
)
94+
]
95+
96+
97+
def handleQuery(query: albert.Query) -> List[albert.Item]:
98+
"""
99+
Handler for a query received from Albert.
100+
"""
101+
query_string = query.string.strip()
102+
match = timezone_regex.fullmatch(query_string)
103+
if match:
104+
try:
105+
return get_items(match.group("from_time"), match.group("to_tz"))
106+
except Exception as error:
107+
albert.warning(f"Error: {error}")
108+
tb = "".join(
109+
traceback.format_exception(error.__class__, error, error.__traceback__)
110+
)
111+
albert.warning(tb)
112+
albert.info(
113+
"Something went wrong. Make sure you're using the correct format."
114+
)

0 commit comments

Comments
 (0)