├── requirements.txt ├── .travis.yml ├── .gitignore ├── README.md └── hacks /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | tqdm 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | - "3.4" 5 | install: 6 | - "pip install -r requirements.txt" 7 | script: 8 | - python hacks 9 | - python hacks --all 10 | - python hacks --version 11 | - python hacks -h 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Hacks 2 | ============ 3 | A Linux terminal client to find upcoming Hackathons near you or at a particular location. 4 | 5 | [![Build Status](https://travis-ci.org/waseem18/Hacks.svg?branch=master)](https://travis-ci.org/waseem18/Hacks) 6 | [![Join the chat at https://gitter.im/waseem18/Hacks](https://badges.gitter.im/waseem18/Hacks.svg)](https://gitter.im/waseem18/Hacks?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 7 | 8 | Installation 9 | -------------- 10 | 1. Clone the repository 11 | ```sh 12 | git clone https://github.com/waseem18/hacks.git && cd hacks 13 | ``` 14 | 15 | 2. Copy the `hacks` executable into your PATH 16 | ```sh 17 | cp hacks /usr/local/bin 18 | ``` 19 | 20 | Commands 21 | -------- 22 | ``` 23 | hacks Outputs details of Hackathons in or near your current location. 24 | hacks [location] Outputs details of Hackathons in or near [location] 25 | hacks --all Outputs details of Hackathons all over the World. 26 | ``` 27 | Examples 28 | -------- 29 | ``` 30 | hacks 31 | hacks California 32 | hacks New York 33 | hacks Canada 34 | hacks Hyderabad 35 | hacks --version 36 | hacks --help 37 | hacks --all 38 | ``` 39 | 40 | Note 41 | -------- 42 | Details of Hackathons have been taken from 43 | 44 | 1. [Hackalist](http://www.hackalist.org) 45 | 2. [Hackathon-Calendar](https://github.com/japacible/Hackathon-Calendar) 46 | 3. [HackathonWatch](http://www.hackathonwatch.com) 47 | 48 | 49 | 50 | Contributions 51 | --------------- 52 | 1. If you know about any upcoming hackathons, add it to [Hackathon-Calendar](https://github.com/japacible/Hackathon-Calendar). If hackathon is particularly from India, add it to [Hackathons-In-India](https://github.com/waseem18/Hackathons-In-India) 53 | 2. Contribute to this repository by removing bugs, improving code efficiency, adding new sources of hackathons etc. I will happily merge it :) 54 | -------------------------------------------------------------------------------- /hacks: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import requests 4 | import datetime 5 | import calendar 6 | import base64 7 | 8 | no_of_arguments = len(sys.argv) 9 | 10 | year = datetime.datetime.now().year 11 | month = datetime.datetime.now().month 12 | day = datetime.datetime.now().day 13 | 14 | 15 | class Hackanswers: 16 | """object to hold information from our sources, to be dissected later.""" 17 | 18 | def fetch(self): 19 | """prepares the object to be queried for results by HackathonsList?(data), 20 | where is the city or location""" 21 | print("Please wait a few seconds while we fetch the details for you...") 22 | self.list1 = [] 23 | self.list2 = [] 24 | self.list3 = [] 25 | self.list4 = [] 26 | fetchalg = [self.fetchHackathonList, 27 | self.fetchHackathonCal, 28 | self.fetchHackathonWatch, 29 | self.fetchHackathonIndia] 30 | try: 31 | import tqdm 32 | fetchalg = tqdm.tqdm(fetchalg) 33 | except ImportError: 34 | pass 35 | for alg in fetchalg: 36 | alg() 37 | 38 | def splitcontent(self, url): 39 | """possible abstraction for splitting request answeres""" 40 | r = requests.get(url) 41 | if r.status_code != 200: 42 | raise RuntimeError 43 | decoded_content = base64.b64decode(r.json()['content']).decode() 44 | return decoded_content.split('\n') 45 | 46 | 47 | # list1[r1,r2] 48 | def fetchHackathonList(self): 49 | url_1_1 = "http://www.hackalist.org/api/1.0/" + str(year) + "/" + "{:02}".format(month) + ".json" 50 | url_1_2 = "http://www.hackalist.org/api/1.0/" + str(year) + "/" + "{:02}".format(month+1) + ".json" 51 | if month == 12: 52 | url_1_2 = "http://www.hackalist.org/api/1.0/" + str(year + 1) + "/" + "01" + ".json" 53 | r1 = requests.get(url_1_1) 54 | if r1.status_code != 200: 55 | print("Couldn't fetch hackalist.org [1]") 56 | else: 57 | self.list1.append(r1.json()) 58 | r2 = requests.get(url_1_2) 59 | if r2.status_code != 200: 60 | print("Couldn't fetch hackalist.org [2]") 61 | else: 62 | self.list1.append(r2.json()) 63 | 64 | def fetchHackathonCal(self): 65 | url_2 = "https://api.github.com/repos/japacible/Hackathon-Calendar/contents/README.md?ref=master" 66 | try: 67 | self.list2.append(self.splitcontent(url_2)) 68 | except RuntimeError: 69 | print("Couldn't fetch Hackathon-Calendar") 70 | 71 | def fetchHackathonWatch(self): 72 | url_3 = "http://hackathonwatch.com:80/api//hackathons/coming.json?page=1" 73 | r = requests.get(url_3) 74 | if r.status_code != 200: 75 | print("Couldn't fetch hackathonwatch.com") 76 | else: 77 | self.list3.append(r.json()) 78 | 79 | def fetchHackathonIndia(self): 80 | url_4 = "https://api.github.com/repos/waseem18/Hackathons-In-India/contents/README.md" 81 | try: 82 | self.list4.append(self.splitcontent(url_4)) 83 | except RuntimeError: 84 | print("Couldn't fetch Hackathons-In-India") 85 | 86 | # initialization 87 | hacks_result = [] 88 | hacks_answer = Hackanswers() 89 | 90 | def HackathonsList1(city, source=hacks_answer, target=None): 91 | data1 = source.list1[0] 92 | data2 = source.list1[1] 93 | if target is None: 94 | target=hacks_result 95 | for i in data1[str(calendar.month_name[month])]: 96 | if city.lower() in (i['host'] + " " + i['city']).lower(): 97 | hack = {} 98 | hack['Title'] = i['title'] 99 | hack['URL'] = i['url'] 100 | if i['highSchoolers'] == "yes": 101 | hack['HighSchoolers'] = "Yes" 102 | else: 103 | hack['HighSchoolers'] = "No" 104 | hack['Starts on'] = i['startDate'] + " " + i['year'] 105 | hack['Ends on'] = i['endDate'] + " " + i['year'] 106 | hack['location'] = i['host'] + " " + i['city'] 107 | if i['travel'] == "" or i['travel'] == "unknown": 108 | hack['Travel'] = "Not mentioned" 109 | elif i['travel'] == "yes": 110 | hack['Travel'] = "Reimbursment provided!" 111 | elif i['travel'] == "no": 112 | hack['Travel'] = "No reimbursment!" 113 | if i['facebookURL'] != "": 114 | hack['Contact'] = "i['facebookURL']" 115 | elif i['twitterURL'] != "": 116 | hack['Contact'] = i['twitterURL'] 117 | target.append(hack) 118 | for i in data2[str(calendar.month_name[1])]: 119 | if city.lower() in (i['host'] + " " + i['city']).lower(): 120 | hack = {} 121 | hack['Title'] = i['title'] 122 | hack['URL'] = i['url'] 123 | if i['highSchoolers'] == "yes": 124 | hack['HighSchoolers'] = "Yes" 125 | else: 126 | hack['HighSchoolers'] = "No" 127 | hack['Starts on'] = i['startDate'] + " " + i['year'] 128 | hack['Ends on'] = i['endDate'] + " " + i['year'] 129 | hack['location'] = i['host'] + " " + i['city'] 130 | if i['travel'] == "" or i['travel'] == "unknown": 131 | hack['travel'] = "Not mentioned!" 132 | elif i['travel'] == "yes": 133 | hack['travel'] = "Reimbursement provided!" 134 | elif i['travel'] == "no": 135 | hack['travel'] = "No reimbursment" 136 | if i['facebookURL'] != "": 137 | hack['Contact'] = i['facebookURL'] 138 | elif i['twitterURL'] != "": 139 | hack['Contact'] = i['twitterURL'] 140 | target.append(hack) 141 | 142 | 143 | def HackathonsList2(city, source=hacks_answer, target=None): 144 | if target is None: 145 | target=hacks_result 146 | decoded_content = source.list2[0] 147 | for i in decoded_content: 148 | hack = {} 149 | if i[0:3] == "| [": 150 | j = 3 151 | title = "" 152 | link = "" 153 | place = "" 154 | duration = "" 155 | while str(i[j]) != "]": 156 | title += i[j] 157 | j += 1 158 | hack['Title'] = title 159 | j += 2 160 | while str(i[j]) != ")": 161 | link += i[j] 162 | j += 1 163 | hack['URL'] = link 164 | j += 4 165 | while str(i[j]) != "|": 166 | place += i[j] 167 | j += 1 168 | hack['location'] = place 169 | j += 2 170 | while str(i[j]) != "|": 171 | duration += i[j] 172 | j += 1 173 | 174 | duration = duration.split('-') 175 | if len(duration) == 1: 176 | start = duration[0].split('.') 177 | hack['Starts on'] = str(calendar.month_name[int(start[0])]) + " " + str(start[1]) 178 | elif len(duration) == 2: 179 | start = duration[0].split('.') 180 | end = duration[1].split('.') 181 | hack['Starts on'] = str(calendar.month_name[int(start[0])]) + " " + str(start[1]) 182 | hack['Ends on'] = str(calendar.month_name[int(end[0])]) + " " + str(end[1]) 183 | if city.lower() in hack['location'].lower(): 184 | target.append(hack) 185 | 186 | 187 | def HackathonsList3(city, source=hacks_answer, target=None): 188 | if target is None: 189 | target=hacks_result 190 | data = source.list3[0] 191 | for i in data: 192 | if city.lower() in i['full_address'].lower(): 193 | hack = {} 194 | hack['Title'] = i['name'] 195 | hack['URL'] = i['public_url'] 196 | duration = int(i['finish_timestamp']) - int(i['start_timestamp']) 197 | hack['Duration'] = str(duration) 198 | # no_of_hours = duration / 3600 199 | hack['Starts on'] = datetime.datetime.fromtimestamp(i['start_timestamp']).strftime( 200 | '%Y-%m-%d %H:%M:%S') 201 | hack['Ends on'] = datetime.datetime.fromtimestamp(i['finish_timestamp']).strftime( 202 | '%Y-%m-%d %H:%M:%S') 203 | hack['location'] = i['full_address'] 204 | target.append(hack) 205 | 206 | 207 | def HackathonsList4(city, source=hacks_answer, target=None): 208 | if target is None: 209 | target=hacks_result 210 | decoded_content = source.list4[0] 211 | for i in decoded_content: 212 | hack = {} 213 | if str(i[0:2]) == "|[": 214 | title = "" 215 | link = "" 216 | location = "" 217 | start = "" 218 | end = "" 219 | j = 2 220 | while i[j] != ']': 221 | title += i[j] 222 | j += 1 223 | hack['Title'] = title 224 | j += 2 225 | while i[j] != ')': 226 | link += i[j] 227 | j += 1 228 | hack['URL'] = link 229 | j += 2 230 | while i[j] != '|': 231 | location += i[j] 232 | j += 1 233 | hack['location'] = location 234 | j += 1 235 | while i[j] != '|': 236 | start += i[j] 237 | j += 1 238 | hack['Starts on'] = start 239 | j += 1 240 | while i[j] != '|': 241 | end += i[j] 242 | j += 1 243 | hack['Ends on'] = end 244 | if city.lower() in hack['location'].lower(): 245 | target.append(hack) 246 | 247 | 248 | def print_help(): 249 | """prints the help string""" 250 | print("Usage:") 251 | print(" 1. Just typing 'hacks' outputs the list of Hackathons in or near your location!\n") 252 | print(" 2. Command 'hacks California' gives the list of Hackathons in California.\n") 253 | print(" 3. We consider all arguments after first arguments as a single argument(city name)).\n") 254 | print(" 4. So command 'hacks New York' too gives the list of Hackathons in New York.\n") 255 | 256 | 257 | def runLists(data): 258 | """call this function with your location as 259 | it will append every valid Hackathon to hacks_result""" 260 | for f in [HackathonsList1, HackathonsList2, HackathonsList3, HackathonsList4]: 261 | try: 262 | f(data) 263 | except: 264 | pass 265 | 266 | def printResults(): 267 | """This print all entries in hacks_result. 268 | Consider running hacks_answer.fetch() beforehand. 269 | """ 270 | print("\n-----------------------------------------------------------------") 271 | for i in hacks_result: 272 | print("Title : " + i['Title']) 273 | print("URL : " + i['URL']) 274 | print("Starts on : " + i['Starts on']) 275 | if 'Ends on' in i: 276 | print("Ends on : " + i['Ends on']) 277 | print("Location : " + i['location']) 278 | print("-----------------------------------------------------------------") 279 | print("") 280 | 281 | def main(): 282 | global hacks_result 283 | global hacks_answer 284 | if no_of_arguments == 1: 285 | # Outputs details of upcoming hackathons in the location of the user. 286 | url = "http://ip-api.com/json" 287 | r = requests.get(url) 288 | data = r.json() 289 | city = str(data['city']) 290 | region = data['regionName'] 291 | country = data['country'] 292 | hacks_answer.fetch() 293 | runLists(city) 294 | runLists(region) 295 | if len(hacks_result) == 0: 296 | print("Looking for Hackathons in %s, %s..." % (region, country)) 297 | runLists(region) # is this line necessary? 298 | runLists(country) # does this make L266-268 redundant? 299 | if len(hacks_result) == 0: 300 | print("Looking for Hackathons in %s..." % (country)) 301 | runLists(country) # can this possibly append something? 302 | if len(hacks_result): 303 | printResults() 304 | else: 305 | print( 306 | "We couldn't find hackathons in %s, %s.\n" 307 | "Try refining the search location Or try the command, 'hacks locationName'.\n" 308 | "Eg: hacks California" % (city, country)) 309 | 310 | elif no_of_arguments == 2: 311 | city = str(sys.argv[1]) 312 | if city == "-h" or city == "--help": 313 | print_help() 314 | sys.exit(0) 315 | elif city == "--version": 316 | print("Hacks - 0.1.1\n") 317 | print("https://github.com/waseem18/hacks\n") 318 | sys.exit(0) 319 | elif city in ["-a", "--all"]: 320 | hacks_answer.fetch() 321 | runLists("") 322 | printResults() 323 | sys.exit(0) 324 | hacks_answer.fetch() 325 | runLists(city) 326 | if len(hacks_result): 327 | printResults() 328 | else: 329 | print( 330 | "We couldn't find hackathons in %s.\n" 331 | "Try refining the search location or find more hackathons at " 332 | "https://github.com/japacible/Hackathon-Calendar" % (city)) 333 | 334 | elif no_of_arguments > 2: 335 | city = " ".join(sys.argv[1:]) 336 | hacks_answer.fetch() 337 | runLists(city) 338 | if len(hacks_result): 339 | printResults() 340 | else: 341 | print( 342 | "We couldn't find hackathons in %s.\n" 343 | "Try refining the search location or find more hackathons at " 344 | "https://github.com/japacible/Hackathon-Calendar" % (city)) 345 | sys.exit(0) 346 | 347 | if __name__ == "__main__": 348 | main() 349 | --------------------------------------------------------------------------------