Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Adobe Offline Package Generator v0.1.2 (macOS only)
#!/bin/bash
CYAN="$(tput bold; tput setaf 6)"
RESET="$(tput sgr0)"
clear
if command -v python3 > /dev/null 2>&1; then
if [ $(python3 -c "print('ye')") = "ye" ]; then
clear
echo "${CYAN}python3 found!${RESET}"
else
clear
echo "python3 found but non-functional" # probably xcode-select stub on Catalina+
echo "${CYAN}If you received a popup asking to install some tools, please accept.${RESET}"
read -n1 -r -p "Press [SPACE] when installation is complete, or any other key to abort." key
echo ""
if [ "$key" != '' ]; then
exit
fi
fi
else
echo "${CYAN}installing python3...${RESET}"
if ! command -v brew > /dev/null 2>&1; then
echo | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
fi
brew install python
fi
python3 -c 'import requests' > /dev/null 2>&1
if [ $? == 0 ]; then
echo "${CYAN}requests found!${RESET}"
else
echo "${CYAN}installing requests...${RESET}"
python3 -m pip install requests --user
fi
clear
echo "${CYAN}starting ccdl${RESET}"
python3 <(curl -s https://gist.githubusercontent.com/ayyybe/a5f01c6f40020f9a7bc4939beeb2df1d/raw/ccdl.py)
#!/usr/bin/env python3
import os
import json
import argparse
import requests
session = requests.Session()
import shutil
from xml.etree import ElementTree as ET
from collections import OrderedDict
from subprocess import Popen, PIPE
VERSION = 3
VERSION_STR = '0.1.2'
INSTALL_APP_APPLE_SCRIPT = '''
const app = Application.currentApplication()
app.includeStandardAdditions = true
ObjC.import('Cocoa')
ObjC.import('stdio')
ObjC.import('stdlib')
ObjC.registerSubclass({
name: 'HandleDataAction',
methods: {
'outData:': {
types: ['void', ['id']],
implementation: function(sender) {
const data = sender.object.availableData
if (data.length !== '0') {
const output = $.NSString.alloc.initWithDataEncoding(data, $.NSUTF8StringEncoding).js
const res = parseOutput(output)
if (res) {
switch (res.type) {
case 'progress':
Progress.additionalDescription = `Progress: ${res.data}%`
Progress.completedUnitCount = res.data
break
case 'exit':
if (res.data === 0) {
$.puts(JSON.stringify({ title: 'Installation succeeded' }))
} else {
$.puts(JSON.stringify({ title: `Failed with error code ${res.data}` }))
}
$.exit(0)
break
}
}
sender.object.waitForDataInBackgroundAndNotify
} else {
$.NSNotificationCenter.defaultCenter.removeObserver(this)
}
}
}
}
})
function parseOutput(output) {
let matches
matches = output.match(/Progress: ([0-9]{1,3})%/)
if (matches) {
return {
type: 'progress',
data: parseInt(matches[1], 10)
}
}
matches = output.match(/Exit Code: ([0-9]{1,3})/)
if (matches) {
return {
type: 'exit',
data: parseInt(matches[1], 10)
}
}
return false
}
function run() {
const args = $.NSProcessInfo.processInfo.arguments
const argv = []
const argc = args.count
for (var i = 0; i < argc; i++) {
argv.push(ObjC.unwrap(args.objectAtIndex(i)))
}
delete args
const installFlag = argv.indexOf('-y') > -1
const appPath = app.pathTo(this).toString()
//const driverPath = appPath.substring(0, appPath.lastIndexOf('/')) + '/products/driver.xml'
const driverPath = appPath + '/Contents/Resources/products/driver.xml'
const hyperDrivePath = '/Library/Application Support/Adobe/Adobe Desktop Common/HDBox/Setup'
if (!installFlag) {
app.displayAlert('Adobe Package Installer', {
message: 'Start installation now?',
buttons: ['Cancel', 'Install'],
defaultButton: 'Install',
cancelButton: 'Cancel'
})
const output = app.doShellScript(`"${appPath}/Contents/MacOS/applet" -y`, { administratorPrivileges: true })
const alert = JSON.parse(output)
alert.params ? app.displayAlert(alert.title, alert.params) : app.displayAlert(alert.title)
return
}
const stdout = $.NSPipe.pipe
const task = $.NSTask.alloc.init
task.executableURL = $.NSURL.alloc.initFileURLWithPath(hyperDrivePath)
task.arguments = $(['--install=1', '--driverXML=' + driverPath])
task.standardOutput = stdout
const dataAction = $.HandleDataAction.alloc.init
$.NSNotificationCenter.defaultCenter.addObserverSelectorNameObject(dataAction, 'outData:', $.NSFileHandleDataAvailableNotification, $.initialOutputFile)
stdout.fileHandleForReading.waitForDataInBackgroundAndNotify
let err = $.NSError.alloc.initWithDomainCodeUserInfo('', 0, '')
const ret = task.launchAndReturnError(err)
if (!ret) {
$.puts(JSON.stringify({
title: 'Error',
params: {
message: 'Failed to launch task: ' + err.localizedDescription.UTF8String
}
}))
$.exit(0)
}
Progress.description = "Installing packages..."
Progress.additionalDescription = "Preparing…"
Progress.totalUnitCount = 100
task.waitUntilExit
}
'''
#ADOBE_PRODUCTS_XML_URL = 'https://prod-rel-ffc-ccm.oobesaas.adobe.com/adobe-ffc-external/core/v4/products/all?_type=xml&channel=ccm,sti&platform=osx10,osx10-64&productType=Desktop'
POPULATE_ADOBE_COOKIES_URL = 'https://adobeid-na1.services.adobe.com/ims/check/v4/token?client_id=CreativeCloud_v5_1'
ADOBE_PRODUCTS_XML_URL = 'https://prod-rel-ffc-ccm.oobesaas.adobe.com/adobe-ffc-external/core/v4/products/all?_type=xml&channel=ccm&platform=osx10-64&productType=Desktop'
ADOBE_APPLICATION_JSON_URL = 'https://prod-rel-ffc-ccm.oobesaas.adobe.com/adobe-ffc-external/core/v2/applications?name={name}&version={version}&platform={platform}'
DRIVER_XML = '''<DriverInfo>
<ProductInfo>
<Name>Adobe {name}</Name>
<SAPCode>{sapCode}</SAPCode>
<CodexVersion>{version}</CodexVersion>
<Platform>osx10-64</Platform>
<EsdDirectory>./{sapCode}</EsdDirectory>
<Dependencies>
{dependencies}
</Dependencies>
</ProductInfo>
<RequestInfo>
<InstallDir>/Applications</InstallDir>
<InstallLanguage>{language}</InstallLanguage>
</RequestInfo>
</DriverInfo>
'''
DRIVER_XML_DEPENDENCY = ''' <Dependency>
<SAPCode>{sapCode}</SAPCode>
<BaseVersion>{version}</BaseVersion>
<EsdDirectory>./{sapCode}</EsdDirectory>
</Dependency>'''
ADOBE_REQ_HEADERS = {
'X-Adobe-App-Id': 'accc-hdcore-desktop',
'User-Agent': 'Adobe Application Manager 2.0',
'X-Api-Key': 'CC_HD_ESD_1_0'
}
def dl(filename, url):
with session.get(url, stream=True, headers=ADOBE_REQ_HEADERS) as r:
with open(filename, 'wb') as f:
shutil.copyfileobj(r.raw, f)
def r(url):
req = session.get(url, headers=ADOBE_REQ_HEADERS)
req.encoding = 'utf-8'
return req.text
def get_products_xml():
return ET.fromstring(r(ADOBE_PRODUCTS_XML_URL))
def parse_products_xml(products_xml):
cdn = products_xml.find('channel/cdn/secure').text
products = {}
for p in products_xml.findall('channel/products/product'):
displayName = p.find('displayName').text
sap = p.get('id')
version = p.get('version')
dependencies = list(p.find('platforms/platform/languageSet/dependencies'))
if not products.get(sap):
products[sap] = {
'displayName': displayName,
'sapCode': sap,
'versions': OrderedDict()
}
products[sap]['versions'][version] = {
'sapCode': sap,
'version': version,
'dependencies': [{
'sapCode': d.find('sapCode').text, 'version': d.find('baseVersion').text
} for d in dependencies]
}
return products, cdn
def get_application_json(sapCode, version):
try:
return json.loads(r(ADOBE_APPLICATION_JSON_URL.format(name=sapCode, version=version, platform='osx10-64')))
except json.decoder.JSONDecodeError:
return json.loads(r(ADOBE_APPLICATION_JSON_URL.format(name=sapCode, version=version, platform='osx10')))
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-l', '--installLanguage', help='Language code (eg. en_US)', action='store')
parser.add_argument('-s', '--sapCode', help='SAP code for desired product (eg. PHSP)', action='store')
parser.add_argument('-v', '--version', help='Version of desired product (eg. 21.0.3)', action='store')
parser.add_argument('-d', '--destination', help='Directory to download installation files to', action='store')
args = parser.parse_args()
print('=================================')
print('= Adobe macOS Package Generator =')
print('============= {} =============\n'.format(VERSION_STR))
if (not os.path.isfile('/Library/Application Support/Adobe/Adobe Desktop Common/HDBox/Setup')):
print('Adobe HyperDrive installer not found.\nPlease make sure the Creative Cloud app is installed.')
exit(1)
print('Populating .adobe.com cookies')
session.post(POPULATE_ADOBE_COOKIES_URL, headers=ADOBE_REQ_HEADERS)
print('Downloading products.xml\n')
products_xml = get_products_xml()
print('Parsing products.xml')
products, cdn = parse_products_xml(products_xml)
print('CDN: ' + cdn)
print(str(len(products)) + ' products found:')
sapCode = None
if (args.sapCode):
if products.get(args.sapCode):
print('\nUsing provided SAP Code: ' + args.sapCode)
sapCode = args.sapCode
else:
print('\nProvided SAP Code not found in products: ' + args.sapCode)
print('')
if not sapCode:
for p in products.values():
print('[{}] {}'.format(p['sapCode'], p['displayName']))
while sapCode is None:
val = input('\nPlease enter the SAP Code of the desired product (eg. PHSP for Photoshop): ')
if val == 'APRO':
print('\033[1;31mAcrobat is currently broken, please sit tight while I try to find a solution.\nAll other products are functional.\033[0m')
elif products.get(val):
sapCode = val
else:
print('{} is not a valid SAP Code. Please use a value from the list above.'.format(val))
product = products.get(sapCode)
versions = product['versions']
version = None
if (args.version):
if versions.get(args.version):
print('\nUsing provided version: ' + args.version)
version = args.version
else:
print('\nProvided version not found: ' + args.version)
print('')
if not version:
for v in reversed(versions.values()):
print('{} {}'.format(product['displayName'], v['version']))
while version is None:
val = input('\nPlease enter the desired version (eg. 21.0.3): ')
if versions.get(val):
version = val
else:
print('{} is not a valid version. Please use a value from the list above.'.format(val))
print('')
langs = [ 'en_US', 'en_GB', 'en_IL', 'en_AE', 'es_ES', 'es_MX', 'pt_BR', 'fr_FR', 'fr_CA', 'fr_MA', 'it_IT', 'de_DE', 'nl_NL', 'ru_RU', 'uk_UA', 'zh_TW', 'zh_CN', 'ja_JP', 'ko_KR', 'pl_PL', 'hu_HU', 'cs_CZ', 'tr_TR', 'sv_SE', 'nb_NO', 'fi_FI', 'da_DK' ]
installLanguage = None
if (args.installLanguage):
if (args.installLanguage in langs):
print('\nUsing provided language: ' + args.installLanguage)
installLanguage = args.installLanguage
else:
print('\nProvided language not available: ' + args.installLanguage)
if not installLanguage:
print('Available languages: {}'.format(', '.join(langs)))
while installLanguage is None:
val = input('\nPlease enter the desired install language, or nothing for [en_US]: ') or 'en_US'
if (val in langs):
installLanguage = val
else:
print('{} is not available. Please use a value from the list above.'.format(val))
dest = None
if (args.destination):
print('\nUsing provided destination: ' + args.destination)
dest = args.destination
else:
print('\nPlease navigate to the desired downloads folder, or cancel to abort.')
p = Popen(['/usr/bin/osascript', '-e', 'tell application (path to frontmost application as text)\nset _path to choose folder\nPOSIX path of _path\nend'], stdout=PIPE)
dest = p.communicate()[0].decode('utf-8').strip()
if (p.returncode != 0):
print('Exiting...')
exit()
print('')
install_app_name = 'Install {}_{}-{}.app'.format(sapCode, version, installLanguage)
install_app_path = os.path.join(dest, install_app_name)
print('sapCode: ' + sapCode)
print('version: ' + version)
print('installLanguage: ' + installLanguage)
print('dest: ' + install_app_path)
prodInfo = versions[version]
prods_to_download = [{ 'sapCode': d['sapCode'], 'version': d['version'] } for d in prodInfo['dependencies']]
prods_to_download.insert(0, { 'sapCode': prodInfo['sapCode'], 'version': prodInfo['version'] })
print('\nCreating {}'.format(install_app_name))
install_app_path = os.path.join(dest, 'Install {}_{}-{}.app'.format(sapCode, version, installLanguage))
with Popen(['/usr/bin/osacompile', '-l', 'JavaScript', '-o', os.path.join(dest, install_app_path)], stdin=PIPE) as p:
p.communicate(INSTALL_APP_APPLE_SCRIPT.encode('utf-8'))
icon_path = '/Library/Application Support/Adobe/Adobe Desktop Common/HDBox/Install.app/Contents/Resources/app.icns'
shutil.copyfile(icon_path, os.path.join(install_app_path, 'Contents', 'Resources', 'applet.icns'))
products_dir = os.path.join(install_app_path, 'Contents', 'Resources', 'products')
print('\nPreparing...\n')
for p in prods_to_download:
s, v = p['sapCode'], p['version']
product_dir = os.path.join(products_dir, s)
app_json_path = os.path.join(product_dir, 'application.json')
print('[{}_{}] Downloading application.json'.format(s, v))
app_json = get_application_json(s, v)
p['application_json'] = app_json
print('[{}_{}] Creating folder for product'.format(s, v))
os.makedirs(product_dir, exist_ok=True)
print('[{}_{}] Saving application.json'.format(s, v))
with open(app_json_path, 'w') as file:
json.dump(app_json, file, separators=(',', ':'))
print('')
print ('Downloading...\n')
for p in prods_to_download:
s, v = p['sapCode'], p['version']
app_json = p['application_json']
product_dir = os.path.join(products_dir, s)
print('[{}_{}] Parsing available packages'.format(s, v))
core_pkg_count = 0
noncore_pkg_count = 0
packages = app_json['Packages']['Package']
download_urls = []
for pkg in packages:
if pkg.get('Type') and pkg['Type'] == 'core':
core_pkg_count += 1
download_urls.append(cdn + pkg['Path'])
else:
if ((not pkg.get('Condition')) or installLanguage in pkg['Condition']): # TODO: actually parse `Condition` and check it properly (and maybe look for & add support for conditions other than installLanguage)
noncore_pkg_count += 1
download_urls.append(cdn + pkg['Path'])
print('[{}_{}] Selected {} core packages and {} non-core packages'.format(s, v, core_pkg_count, noncore_pkg_count))
for url in download_urls:
name = url.split('/')[-1].split('?')[0]
print('[{}_{}] Downloading {}'.format(s, v, name))
dl(os.path.join(product_dir, name), url)
print('\nGenerating driver.xml')
driver = DRIVER_XML.format(
name = product['displayName'],
sapCode = prodInfo['sapCode'],
version = prodInfo['version'],
dependencies = '\n'.join([DRIVER_XML_DEPENDENCY.format(
sapCode = d['sapCode'],
version = d['version']
) for d in prodInfo['dependencies']]),
language = installLanguage
)
with open(os.path.join(products_dir, 'driver.xml'), 'w') as f:
f.write(driver)
f.close()
print('\nPackage successfully created. Run {} to install.'.format(install_app_path))
#!/bin/bash
CYAN="$(tput bold; tput setaf 6)"
RESET="$(tput sgr0)"
curl https://gist.githubusercontent.com/ayyybe/a5f01c6f40020f9a7bc4939beeb2df1d/raw/ccdl.command -o "/Applications/Adobe Packager.command"
chmod +x "/Applications/Adobe Packager.command"
clear
echo "${CYAN}Done! You can now start /Applications/Adobe Packager.command to begin${RESET}"
exit
@dukuo

This comment has been minimized.

Copy link

dukuo commented May 8, 2020

Hi thanks for sharing! Would you know any links towards a Windows version?
Cheers!

@ayyybe

This comment has been minimized.

Copy link
Owner Author

ayyybe commented May 8, 2020

CCMaker works pretty well for Windows. I don't know which sources for it are safe so I won't link any, but you should be able to find it easily.

@Col0nelPan1c

This comment has been minimized.

Copy link

Col0nelPan1c commented May 9, 2020

Totally incompetent unknowledgable unworthy noob here, (self deprecation is the highest form of AI Flattery I’m told) so please forgive me in advance...

I know from my endless hours of research amongst 3 trusted & reliable sources that I should be looking to acquire (slightly) previous versions of the Adobe apps than what are offered via CC, for a slew of reasons. I also know that this “code block” does exactly that, which is great..

However, I am “Terminal Deficient” at the highest order, & so a combined ~430 lines of code would surely result in my laptop spontaneously combusting merely 1/2-through...

Can the entire block be copy/pasted? Do I have to have X Code, HomeBrew, or Command Line Tools installed? Is there any similar method for acquiring these installers that is slightly more GUI based?

Lastly, based on the content of my queries, & the lack of competency they so clearly demonstrate, is it a pretty safe assumption that I should keep looking for a method to acquire adobe installers? (Early CC 2020 was my general target zone, but certainly I would be thrilled w/ even say the latest 2019 CC, OR EVEN a mid-late 2019, if it had the advantage of more simplicity in the install process etc.

Sorry to pollute your comment thread here with this, just hoping that either someone pity’s me enough to help me in my (narrowly focused) quest, &/or can point me in the direction of an alternative solution.

Thx for all your hard work, Genuinely hope I’m not out of order with my question here.

@ayyybe

This comment has been minimized.

Copy link
Owner Author

ayyybe commented May 9, 2020

@Col0nelPan1c you can just run /bin/bash -c "$(curl -fsSL https://gist.githubusercontent.com/ayyybe/a5f01c6f40020f9a7bc4939beeb2df1d/raw/install.sh)" in Terminal, and then run "Adobe Packager.command" in your /Applications folder. It should be able to automatically configure itself in most setups.

@Col0nelPan1c

This comment has been minimized.

Copy link

Col0nelPan1c commented May 9, 2020

Thank you so very much. Wish me luck, I shall embark upon this new frontier posthaste!

@kay-dotcom

This comment has been minimized.

Copy link

kay-dotcom commented May 13, 2020

@Col0nelPan1c you can just run /bin/bash -c "$(curl -fsSL https://gist.githubusercontent.com/ayyybe/a5f01c6f40020f9a7bc4939beeb2df1d/raw/install.sh)" in Terminal, and then run "Adobe Packager.command" in your /Applications folder. It should be able to automatically configure itself in most setups.

Hi there, how do I fin Adobe Packager.command? I don't see it in my applications folder.

@alouanemed

This comment has been minimized.

Copy link

alouanemed commented May 27, 2020

I am getting this after launching the app

Populating .adobe.com cookies
Downloading products.xml

Traceback (most recent call last):
  File "/dev/fd/63", line 244, in <module>
  File "/dev/fd/63", line 189, in get_products_xml
  File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/xml/etree/ElementTree.py", line 1316, in XML
    return parser.close()
xml.etree.ElementTree.ParseError: no element found: line 1, column 0
logout
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

[Process completed]


@idarek

This comment has been minimized.

Copy link

idarek commented Jun 5, 2020

Working perfectly by following in terminal
/bin/bash -c "$(curl -fsSL https://gist.githubusercontent.com/ayyybe/a5f01c6f40020f9a7bc4939beeb2df1d/raw/install.sh)"

and than running command from /Applications through terminal. Thanks.

@chriswayg

This comment has been minimized.

Copy link

chriswayg commented Jun 30, 2020

Nice script @ayyybe, which works very well! - I forked it and added some documentation as well as a binary built with pyinstaller. You can check it out here:

https://github.com/chriswayg/CC-Offline-Package-Generator (MOVED)

This should also help users like @Col0nelPan1c who asked above:

However, I am “Terminal Deficient” at the highest order, ...
Is there any similar method for acquiring these installers that is slightly more GUI based?

@frankyw

This comment has been minimized.

Copy link

frankyw commented Jul 1, 2020

Nice script @ayyybe, which works very well! - I forked it and added some documentation as well as a binary built with pyinstaller. You can check it out here:

https://github.com/chriswayg/Adobe-Offline-Package-Generator

Very nice @chriswayg and @ayyybe, worked perfectly on Catalina 10.15.5. Hopefully we can keep this updated in a proper repo, as this is much better than looking for links on reddit.

@chriswayg

This comment has been minimized.

Copy link

chriswayg commented Jul 7, 2020

Very nice @chriswayg and @ayyybe, worked perfectly on Catalina 10.15.5. Hopefully we can keep this updated in a proper repo, as this is much better than looking for links on reddit.

I am glad you like it, @frankyw. I cleaned up and moved the repo to this location:

MOVED TO: https://github.com/chriswayg/CC-Offline-Package-Generator

I hope @ayyybe will be able to continue to improve the script which does the actual work. I merely created an easy to install wrapper.

@chriswayg

This comment has been minimized.

Copy link

chriswayg commented Jul 7, 2020

I was able to reproduce: Install MUSE_2018.1.1-en_AE.app Failed with error code 182 installation error

I get the same result on Mojave in /Library/Logs/Adobe/Installers/Install.log

FATAL: Package Zip '/Users/editor/Desktop/Install MUSE_2018.1.1-en_US.app/Contents/Resources/products/./MUSE/AdobeMuse2018.1.1-legal.zip' is not present in ESD Mode
FATAL: Error occurred in install product workflow with error code 182 error message 

Using dummy files will get to this point in the log:

 Completed 'DOWNLOAD' task for Package (Name: AdobeMuse2018.1.1-core Version: 2018.1.1.29), Time taken '0' sec 
 Completed 'DOWNLOAD' task for Package (Name: AdobeMuse2018.1.1-en_US Version: 2018.1.1.29), Time taken '0' sec 

It is looking for two files which are missing:

 Completed 'DOWNLOAD' task for Package (Name: AdobeMuse2018.1.1-legal Version: 2018.1.1.29), Time taken '0' sec 
 Completed 'DOWNLOAD' task for Package (Name: AdobeMuse2018.1.1-AMT Version: 2018.1.1.29), Time taken '0' sec 

@ayyybe, how would you fetch these files from Adobe in Python code?

@naeepalm

This comment has been minimized.

Copy link

naeepalm commented Jul 16, 2020

Screen Shot 2020-07-15 at 8 43 47 PM

Hello, there something wrong with the script. I keep getting this error. I did it once already and it worked perfectly but now this script error keeps happening. Can you help?
@Schrodingers-Neko

This comment has been minimized.

Copy link

Schrodingers-Neko commented Jul 24, 2020

It worked, thanks a lot! I only have one suggestion: add a progress bar like "#############................." and a percentage for downloading.

@luanafaustini

This comment has been minimized.

Copy link

luanafaustini commented Aug 3, 2020

All perfectly installed at Catalina 10.15.6. Thank you for saving my a**!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.