Skip to content

Commit 7b8418c

Browse files
author
4vian5
authored
Add files via upload
0 parents  commit 7b8418c

File tree

6 files changed

+286
-0
lines changed

6 files changed

+286
-0
lines changed

README.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Skillshare-DL
2+
3+
<h4>📝 Note: Downloader core is not written by me. i found this python downloader from a forum. i did few modification to code then implemented it into colab. all credit goes to original python script dev.</h4>
4+
5+
6+
## Disclaimer
7+
8+
I will not be responsible for how you use Skillshare-DL
9+
Although the downloaded files are not the contents themselves, accessing or storing these files might still be illegal in some parts of the world. So, take great care when using this tool and make sure that it is legal.
10+
"# skillshare-dl"
11+
"# skillshare-dl"

Skillshare_DL_[1hack].ipynb

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
{
2+
"nbformat": 4,
3+
"nbformat_minor": 0,
4+
"metadata": {
5+
"colab": {
6+
"name": "Skillshare_DL_[1hack]",
7+
"provenance": [],
8+
"collapsed_sections": [],
9+
"authorship_tag": "ABX9TyNPhPXQUcZNpZ/CJqEWS5sL",
10+
"include_colab_link": true
11+
},
12+
"kernelspec": {
13+
"name": "python3",
14+
"display_name": "Python 3"
15+
}
16+
},
17+
"cells": [
18+
{
19+
"cell_type": "markdown",
20+
"metadata": {
21+
"id": "view-in-github",
22+
"colab_type": "text"
23+
},
24+
"source": [
25+
"<a href=\"https://colab.research.google.com/github/beast1hack/skillshare-1hack/blob/master/Skillshare_DL_%5B1hack%5D.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
26+
]
27+
},
28+
{
29+
"cell_type": "code",
30+
"metadata": {
31+
"id": "IPSBl3OUzsw7",
32+
"colab_type": "code",
33+
"cellView": "form",
34+
"colab": {}
35+
},
36+
"source": [
37+
"#@markdown <h3>⬅ Run This Cell to Mount Gdrive\n",
38+
"from google.colab import drive\n",
39+
"drive.mount('/content/drive')"
40+
],
41+
"execution_count": 0,
42+
"outputs": []
43+
},
44+
{
45+
"cell_type": "code",
46+
"metadata": {
47+
"id": "a-pB9svOzznW",
48+
"colab_type": "code",
49+
"cellView": "form",
50+
"colab": {}
51+
},
52+
"source": [
53+
"#@markdown <h3>⬅️ Run This Cell to Install Skillshare-DL Requirements</h3>\n",
54+
"import random, string, urllib.request, json, getpass, os, IPython, uuid\n",
55+
"import ipywidgets as widgets\n",
56+
"\n",
57+
"from IPython.display import HTML, clear_output\n",
58+
"\n",
59+
"loadingBtn = widgets.Button(description = \"Installing\",\n",
60+
" disabled = True,\n",
61+
" button_style = 'warning', # 'success', 'info', 'warning', 'danger' or '' \n",
62+
" tooltip = \"Installing\",\n",
63+
" icon = 'check')\n",
64+
"display(loadingBtn)\n",
65+
"\n",
66+
"if not os.path.exists(\"/opt/python3.7\"):\n",
67+
" get_ipython().system_raw(\"rm -rf /content/sample_data/ && sudo apt update && sudo apt install software-properties-common\")\n",
68+
" get_ipython().system_raw(\"sudo add-apt-repository ppa:deadsnakes/ppa\")\n",
69+
" get_ipython().system_raw(\"sudo apt install python3.7\")\n",
70+
" get_ipython().system_raw(\"sudo apt install python3-pip\")\n",
71+
" get_ipython().system_raw(\"python3.7 -m pip install --upgrade pip setuptools wheel\")\n",
72+
" get_ipython().system_raw(\"git clone https://github.com/beast1hack/skillshare-1hack.git /root/.skillshare-1hack\")\n",
73+
" get_ipython().system_raw(\"rm -r /root/.skillshare-1hack/Skillshare_DL_[1hack].ipynb\")\n",
74+
" clear_output()\n",
75+
"\n",
76+
"try:\n",
77+
" get_ipython().system_raw(\"python3.7 -m pip -q install -r /root/.skillshare-1hack/requirements.txt\")\n",
78+
" display(HTML(\"<center><h2 style=\\\"font-family:Trebuchet MS;color:#4f8bd6;\\\">Successfully Configured!</h2><br></center>\"))\n",
79+
" \n",
80+
"except:\n",
81+
" display(HTML(\"<center><h2 style=\\\"font-family:Trebuchet MS;color:#ff0000;\\\">Error Occured, Rerun the Cell!!</h2><br></center>\")) "
82+
],
83+
"execution_count": 0,
84+
"outputs": []
85+
},
86+
{
87+
"cell_type": "code",
88+
"metadata": {
89+
"id": "I7zT2rUX0KM4",
90+
"colab_type": "code",
91+
"cellView": "form",
92+
"colab": {}
93+
},
94+
"source": [
95+
"#@markdown <h3>⬅️ Run this Cell to Download Skillshare Course</h3>\n",
96+
"Course_Link = \"\" #@param {type:\"string\"}\n",
97+
"!python3.7 /root/.skillshare-1hack/dl.py \"$Course_Link\""
98+
],
99+
"execution_count": 0,
100+
"outputs": []
101+
},
102+
{
103+
"cell_type": "code",
104+
"metadata": {
105+
"id": "v6fDZLoz0NSm",
106+
"colab_type": "code",
107+
"cellView": "form",
108+
"colab": {}
109+
},
110+
"source": [
111+
"#@markdown <h3>⬅️ Run This Cell to Move Downloaded Courses to Gdrive\n",
112+
"!mv /content/Skillshare \"/content/drive/My Drive/Skillshare-DL\""
113+
],
114+
"execution_count": 0,
115+
"outputs": []
116+
}
117+
]
118+
}

dl.py

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import sys, os
2+
from skillshare import Skillshare
3+
from magic import cookie
4+
5+
# or by class ID:
6+
# dl.download_course_by_class_id(189505397)
7+
8+
def main():
9+
dl = Skillshare(cookie)
10+
course_url = sys.argv[1]
11+
dl.download_course_by_url(course_url)
12+
13+
14+
def info():
15+
print(r"""
16+
17+
▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄ ▄
18+
▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌ ▐░░░░░░░░░░▌ ▐░▌
19+
▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌ ▀▀▀▀█░█▀▀▀▀ ▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌▐░▌
20+
▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌
21+
▐░█▄▄▄▄▄▄▄▄▄ ▐░▌░▌ ▐░▌ ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌▐░▌
22+
▐░░░░░░░░░░░▌▐░░▌ ▐░▌ ▐░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌
23+
▀▀▀▀▀▀▀▀▀█░▌▐░▌░▌ ▐░▌ ▐░▌ ▐░▌ ▀▀▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀█░█▀▀ ▐░█▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░▌
24+
▐░▌▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌
25+
▄▄▄▄▄▄▄▄▄█░▌▐░▌ ▐░▌ ▄▄▄▄█░█▄▄▄▄ ▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄█░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄
26+
▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌ ▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌
27+
▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀
28+
29+
▄▄▄▄▄▄▄▄▄▄▄ ▄▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄
30+
▐░░░░░░░░░░░▌▐░░▌ ▐░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌ ▐░▌ ▐░▌▐░░░░░░░░░░░▌
31+
▐░█▀▀▀▀▀▀▀█░▌▐░▌░▌ ▐░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░█▀▀▀▀▀▀▀▀▀
32+
▐░▌ ▐░▌▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌
33+
▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌▐░▌ ▐░▌░▌ ▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄▄▄
34+
▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░░▌ ▐░▌ ▐░▌▐░░░░░░░░░░░▌
35+
▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌▐░▌ ▐░▌░▌ ▐░▌ ▐░▌ ▀▀▀▀▀▀▀▀▀█░▌
36+
▐░▌ ▐░▌▐░▌ ▐░▌▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌
37+
▐░█▄▄▄▄▄▄▄█░▌▐░▌ ▐░▐░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌ ▄ ▐░█▄▄▄▄▄▄▄█░▌ ▄▄▄▄▄▄▄▄▄█░▌
38+
▐░░░░░░░░░░░▌▐░▌ ▐░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌
39+
▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀
40+
41+
42+
43+
Visit Us for more Cool Stuff: https://onehack.us/
44+
45+
""")
46+
47+
48+
if __name__ == "__main__":
49+
info()
50+
main()

magic.pyc

2.49 KB
Binary file not shown.

requirements.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
python-slugify
2+
requests

skillshare.py

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import requests, json, sys, re, os
2+
from slugify import slugify
3+
4+
class Skillshare(object):
5+
6+
def __init__(
7+
self,
8+
cookie,
9+
download_path=os.environ.get('FILE_PATH', './Skillshare'),
10+
pk='BCpkADawqM2OOcM6njnM7hf9EaK6lIFlqiXB0iWjqGWUQjU7R8965xUvIQNqdQbnDTLz0IAO7E6Ir2rIbXJtFdzrGtitoee0n1XXRliD-RH9A-svuvNW9qgo3Bh34HEZjXjG4Nml4iyz3KqF',
11+
brightcove_account_id=3695997568001,
12+
):
13+
self.cookie = cookie.strip().strip('"')
14+
self.download_path = download_path
15+
self.pk = pk.strip()
16+
self.brightcove_account_id = brightcove_account_id
17+
self.pythonversion = 3 if sys.version_info >= (3, 0) else 2
18+
19+
def is_unicode_string(self, string):
20+
if (self.pythonversion == 3 and isinstance(string, str)) or (self.pythonversion == 2 and isinstance(string, unicode)):
21+
return True
22+
23+
else:
24+
return False
25+
26+
def download_course_by_url(self, url):
27+
m = re.match('https://www.skillshare.com/classes/.*?/(\\d+)', url)
28+
assert m, 'Failed to parse class ID from URL'
29+
self.download_course_by_class_id(m.group(1))
30+
31+
def download_course_by_class_id(self, class_id):
32+
data = self.fetch_course_data_by_class_id(class_id=class_id)
33+
teacher_name = None
34+
if 'vanity_username' in data['_embedded']['teacher']:
35+
teacher_name = data['_embedded']['teacher']['vanity_username']
36+
if not teacher_name:
37+
teacher_name = data['_embedded']['teacher']['full_name']
38+
assert teacher_name, 'Failed to read teacher name from data'
39+
if self.is_unicode_string(teacher_name):
40+
teacher_name = teacher_name.encode('ascii', 'replace')
41+
title = data['title']
42+
if self.is_unicode_string(title):
43+
title = title.encode('ascii', 'replace')
44+
base_path = os.path.abspath(os.path.join(self.download_path, slugify(teacher_name), slugify(title))).rstrip('/')
45+
if not os.path.exists(base_path):
46+
os.makedirs(base_path)
47+
for u in data['_embedded']['units']['_embedded']['units']:
48+
for s in u['_embedded']['sessions']['_embedded']['sessions']:
49+
video_id = None
50+
if 'video_hashed_id' in s:
51+
if s['video_hashed_id']:
52+
video_id = s['video_hashed_id'].split(':')[1]
53+
assert video_id, 'Failed to read video ID from data'
54+
s_title = s['title']
55+
if self.is_unicode_string(s_title):
56+
s_title = s_title.encode('ascii', 'replace')
57+
file_name = '{} - {}'.format(str(s['index'] + 1).zfill(2), slugify(s_title))
58+
self.download_video(fpath='{base_path}/{session}.mp4'.format(base_path=base_path,
59+
session=file_name),
60+
video_id=video_id)
61+
print('')
62+
63+
def fetch_course_data_by_class_id(self, class_id):
64+
res = requests.get(url=('https://api.skillshare.com/classes/{}'.format(class_id)),
65+
headers={'Accept':'application/vnd.skillshare.class+json;,version=0.8',
66+
'User-Agent':'Skillshare/4.1.1; Android 5.1.1',
67+
'Host':'api.skillshare.com',
68+
'cookie':self.cookie})
69+
assert res.status_code == 200, 'Fetch error, code == {}'.format(res.status_code)
70+
return res.json()
71+
72+
def download_video(self, fpath, video_id):
73+
meta_url = 'https://edge.api.brightcove.com/playback/v1/accounts/{account_id}/videos/{video_id}'.format(account_id=(self.brightcove_account_id),
74+
video_id=video_id)
75+
meta_res = requests.get(meta_url,
76+
headers={'Accept':'application/json;pk={}'.format(self.pk),
77+
'User-Agent':'Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0',
78+
'Origin':'https://www.skillshare.com'})
79+
assert not meta_res.status_code != 200, 'Failed to fetch video meta'
80+
for x in meta_res.json()['sources']:
81+
if 'container' in x:
82+
if x['container'] == 'MP4' and 'src' in x:
83+
dl_url = x['src']
84+
break
85+
86+
print('Downloading {}...'.format(fpath))
87+
if os.path.exists(fpath):
88+
print('Video already downloaded, skipping...')
89+
return
90+
with open(fpath, 'wb') as (f):
91+
response = requests.get(dl_url, allow_redirects=True, stream=True)
92+
total_length = response.headers.get('content-length')
93+
if not total_length:
94+
f.write(response.content)
95+
else:
96+
dl = 0
97+
total_length = int(total_length)
98+
for data in response.iter_content(chunk_size=4096):
99+
dl += len(data)
100+
f.write(data)
101+
done = int(50 * dl / total_length)
102+
sys.stdout.write('\r[%s%s]' % ('=' * done, ' ' * (50 - done)))
103+
sys.stdout.flush()
104+
105+
print('')

0 commit comments

Comments
 (0)