+def _remove_utm(link):
+ parsed_link = urlparse(link)
+ parsed_link = parsed_link._replace(
+ query='&'.join(
+ [
+ p
+ for p in parsed_link.query.split('&')
+ if not p.startswith('utm_')
+ ]
+ )
+ )
+
+ return ''.join((
+ parsed_link.scheme + '://' if parsed_link.scheme else '',
+ parsed_link.netloc,
+ parsed_link.path,
+ ';' + parsed_link.params if parsed_link.params else '',
+ '?' + parsed_link.query if parsed_link.query else '',
+ '#' + parsed_link.fragment if parsed_link.fragment else '',
+ ))
+
+def _follow_redirects(link, remove_utm):
+ while True:
+ if remove_utm:
+ link = _remove_utm(link)
+
+ response = requests.head(link)
+
+ # TODO Handle timeouts
+
+ if 301 <= response.status_code and response.status_code <= 308:
+ # TODO Handle the different kinds of redirects correctly
+
+ link = response.headers.get('Location')
+
+ if not link:
+ # TODO Handle this
+ raise Exception()
+
+ # TODO Handle error responses
+ else:
+ return {
+ 'link': link,
+ 'status': response.status_code,
+ }
+