├── .gitignore
├── pyproject.toml
├── setup.py
├── unimi_dl
├── __main__.py
├── __init__.py
├── platform
│ ├── __init__.py
│ ├── platform.py
│ ├── getPlatform.py
│ ├── ariel.py
│ └── panopto.py
├── multi_select.py
└── cmd.py
├── setup.cfg
├── CHANGELOG.md
├── README_EN.md
├── README.md
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | /*.egg-info
2 | /dist/*
3 | __pycache__
4 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["setuptools", "wheel"]
3 | build-backend = "setuptools.build_meta"
4 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Copyright (C) 2021 Alessandro Clerici Lorenzini and Zhifan Chen.
4 | #
5 | # This file is part of unimi-dl.
6 | #
7 | # unimi-dl is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # unimi-dl is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with unimi-dl. If not, see .
19 |
20 |
21 | from setuptools import setup
22 |
23 | setup()
24 |
--------------------------------------------------------------------------------
/unimi_dl/__main__.py:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2021 Alessandro Clerici Lorenzini and Zhifan Chen.
2 | #
3 | # This file is part of unimi-dl.
4 | #
5 | # unimi-dl is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # unimi-dl is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with unimi-dl. If not, see .
17 |
18 |
19 | from .cmd import main
20 |
21 | if __name__ == '__main__':
22 | main()
23 |
--------------------------------------------------------------------------------
/unimi_dl/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2021 Alessandro Clerici Lorenzini and Zhifan Chen.
2 | #
3 | # This file is part of unimi-dl.
4 | #
5 | # unimi-dl is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # unimi-dl is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with unimi-dl. If not, see .
17 |
18 |
19 | __version__ = "0.3.1"
20 | __license__ = "GPL v.3"
21 |
22 | import unimi_dl.platform
23 |
24 | __all__ = ["cmd"]
25 |
--------------------------------------------------------------------------------
/unimi_dl/platform/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2021 Alessandro Clerici Lorenzini and Zhifan Chen.
2 | #
3 | # This file is part of unimi-dl.
4 | #
5 | # unimi-dl is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # unimi-dl is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with unimi-dl. If not, see .
17 |
18 |
19 | from .getPlatform import getPlatform
20 | from .ariel import Ariel
21 | from .panopto import Panopto
22 |
23 | __all__ = ["ariel", "getPlatform", "panopto", "platform"]
24 |
--------------------------------------------------------------------------------
/unimi_dl/platform/platform.py:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2021 Alessandro Clerici Lorenzini and Zhifan Chen.
2 | #
3 | # This file is part of unimi-dl.
4 | #
5 | # unimi-dl is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # unimi-dl is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with unimi-dl. If not, see .
17 |
18 |
19 | from __future__ import annotations
20 |
21 |
22 | class Platform:
23 | def __init__(self, email: str, password: str) -> None:
24 | self.email = email
25 | self.password = password
26 |
27 | def get_manifests(self, url: str) -> dict[str, str]:
28 | """ Returns a list of couples, each one containing a filename and relative
29 | manifest, fetched from {url} """
30 |
31 | raise NotImplementedError
32 |
--------------------------------------------------------------------------------
/unimi_dl/multi_select.py:
--------------------------------------------------------------------------------
1 | class WrongSelectionError(Exception):
2 | pass
3 |
4 |
5 | def multi_select(entries: list, entries_text: list = None, selection_text: str = "\nYour selection: ") -> list:
6 | if not entries_text:
7 | entries_text = entries
8 | elif len(entries_text) != len(entries):
9 | raise ValueError("entries and entries_text must have the same length")
10 |
11 | for i, item in enumerate(entries_text):
12 | print("%d.\t%s" % (i+1, item))
13 | menu_input = input(selection_text)
14 |
15 | ranges = menu_input.strip().split(",")
16 | sel_indexes = set()
17 | if len(ranges) == 1 and ranges[0] == "":
18 | return []
19 | for rang in ranges:
20 | extremes = rang.split("-")
21 | if not 1 <= len(extremes) <= 2:
22 | raise WrongSelectionError
23 | try:
24 | extremes = [int(n)-1 for n in extremes]
25 | except ValueError:
26 | raise WrongSelectionError
27 | if len(extremes) == 1:
28 | extremes.append(extremes[0])
29 | sel_indexes.update(range(extremes[0], extremes[1]+1))
30 |
31 | try:
32 | return [entries[i] for i in sel_indexes]
33 | except IndexError:
34 | raise WrongSelectionError
35 |
--------------------------------------------------------------------------------
/unimi_dl/platform/getPlatform.py:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2021 Alessandro Clerici Lorenzini and Zhifan Chen.
2 | #
3 | # This file is part of unimi-dl.
4 | #
5 | # unimi-dl is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # unimi-dl is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with unimi-dl. If not, see .
17 |
18 | from __future__ import annotations
19 |
20 | from .ariel import Ariel
21 | from .panopto import Panopto
22 | from .platform import Platform
23 |
24 |
25 | def getPlatform(email: str, password: str, platform: str) -> Platform:
26 | """ Factory method to create the appropriate Platform instance. """
27 |
28 | if platform == 'ariel':
29 | return Ariel(email, password)
30 | if platform == 'panopto':
31 | return Panopto(email, password)
32 |
33 | raise NotImplementedError
34 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2021 Alessandro Clerici Lorenzini and Zhifan Chen.
2 | #
3 | # This file is part of unimi-dl.
4 | #
5 | # unimi-dl is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # unimi-dl is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with unimi-dl. If not, see .
17 |
18 |
19 | [metadata]
20 | name = unimi-dl
21 | version = attr: unimi_dl.__version__
22 | author = Alessandro Clerici Lorenzini and Zhifan Chen.
23 | description = Script used for downloading videos from Unimi portals
24 | long_description = file: README.md
25 | long_description_content_type = text/markdown
26 | url = https://github.com/SimpoLab/unimi-dl
27 | project_urls =
28 | Bug Tracker = https://github.com/SimpoLab/unimi-dl/issues
29 | classifiers =
30 | Development Status :: 4 - Beta
31 | Environment :: Console
32 | License :: OSI Approved :: GNU General Public License v3 (GPLv3)
33 | Operating System :: MacOS
34 | Operating System :: Microsoft :: Windows
35 | Operating System :: POSIX :: Linux
36 | Programming Language :: Python
37 | Programming Language :: Python :: 3
38 | Topic :: Education
39 | Topic :: Multimedia
40 | license = attr: unimi_dl.__license__
41 | license_file = LICENSE
42 | keywords = unimi, download, ariel, panopto, labonline
43 | scripts = unimi_dl/cmd.py
44 |
45 |
46 | [options]
47 | packages =
48 | unimi_dl
49 | unimi_dl.platform
50 | python_requires = >=3.8
51 | install_requires =
52 | requests
53 | youtube-dl
54 |
55 |
56 | [options.entry_points]
57 | console_scripts =
58 | unimi-dl = unimi_dl.cmd:main
59 |
--------------------------------------------------------------------------------
/unimi_dl/platform/ariel.py:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2021 Alessandro Clerici Lorenzini and Zhifan Chen.
2 | #
3 | # This file is part of unimi-dl.
4 | #
5 | # unimi-dl is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # unimi-dl is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with unimi-dl. If not, see .
17 |
18 |
19 | from __future__ import annotations
20 | import logging
21 | import re
22 | import urllib.parse
23 |
24 | import requests
25 |
26 | from .platform import Platform
27 |
28 |
29 | def get_ariel_session(email: str, password: str) -> requests.Session:
30 | s = requests.Session()
31 | login_url = 'https://elearning.unimi.it/authentication/skin/portaleariel/login.aspx?url=https://ariel.unimi.it/'
32 | payload = {'hdnSilent': 'true',
33 | 'tbLogin': email,
34 | 'tbPassword': password}
35 | s.post(login_url, data=payload)
36 | return s
37 |
38 |
39 | class Ariel(Platform):
40 | def __init__(self, email: str, password: str) -> None:
41 | super().__init__(email, password)
42 | self.logger = logging.getLogger(__name__)
43 | self.logger.info("Logging in")
44 | self.session = get_ariel_session(email, password)
45 |
46 | def get_manifests(self, url: str) -> dict[str, str]:
47 | self.logger.info("Getting video page")
48 | video_page = self.session.get(url).text
49 |
50 | self.logger.info("Collecting manifests and video names")
51 | res = {}
52 | manifest_re = re.compile(
53 | r"https://.*?/mp4:.*?([^/]*?)\.(m4v|mp4)/manifest.m3u8")
54 | for i, manifest in enumerate(manifest_re.finditer(video_page)):
55 | title = urllib.parse.unquote(
56 | manifest[1]) if manifest[1] else urllib.parse.urlparse(url)[1]+str(i)
57 | while title in res:
58 | title += "_other"
59 | res[title] = manifest[0]
60 | return res
61 |
--------------------------------------------------------------------------------
/unimi_dl/platform/panopto.py:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2021 Alessandro Clerici Lorenzini and Zhifan Chen.
2 | #
3 | # This file is part of unimi-dl.
4 | #
5 | # unimi-dl is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # unimi-dl is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with unimi-dl. If not, see .
17 |
18 |
19 | from __future__ import annotations
20 | import logging
21 | import re
22 |
23 | import requests
24 | from urllib3 import disable_warnings
25 | import urllib.parse
26 | from urllib3.exceptions import InsecureRequestWarning
27 |
28 | from .ariel import get_ariel_session
29 | from .platform import Platform
30 |
31 |
32 | def get_panopto_session(email: str, password: str) -> requests.Session:
33 | s = get_ariel_session(email, password)
34 | auth_url = r"https://unimi.cloud.panopto.eu/Panopto/Pages/Auth/Login.aspx?instance=Labonline"
35 | disable_warnings(InsecureRequestWarning)
36 | s.get(auth_url, verify=False)
37 | return s
38 |
39 |
40 | class Panopto(Platform):
41 | def __init__(self, email: str, password: str) -> None:
42 | super().__init__(email, password)
43 | self.logger = logging.getLogger(__name__)
44 | self.logger.info("Logging in")
45 | self.session = get_panopto_session(email, password)
46 |
47 | def get_manifests(self, url: str) -> dict[str, str]:
48 | self.logger.info("Getting video page")
49 | video_page = self.session.get(url).text
50 |
51 | iframe_re = re.compile(r"