forked from kenzuya/unshackle
feat(netflix): support templated Android ESN generation
Add support for `{randomchar_N}` placeholders in Netflix Android `esn_map` values and generate those segments at runtime. Reuse a cached ESN only when it matches the derived template pattern, is Android-typed, and is not expired; otherwise regenerate and refresh the cache.
This keeps static ESN mappings working as before while enabling dynamic ESN templates (e.g., system_id `7110`) to avoid fixed identifiers and keep ESNs valid per template.
This commit is contained in:
@@ -708,20 +708,44 @@ class Netflix(Service):
|
||||
def get_esn(self):
|
||||
if self.cdm.device_type == DeviceTypes.ANDROID:
|
||||
try:
|
||||
# Use ESN map from config.yaml instead of generating a new one
|
||||
esn = self.config["esn_map"][self.cdm.system_id]
|
||||
esn_template = self.config["esn_map"][self.cdm.system_id]
|
||||
except KeyError:
|
||||
self.log.error(f"ESN mapping not found for system_id: {self.cdm.system_id}")
|
||||
raise Exception(f"ESN mapping not found for system_id: {self.cdm.system_id}")
|
||||
|
||||
esn_value = {
|
||||
'esn': esn,
|
||||
'type': self.cdm.device_type
|
||||
}
|
||||
cached_esn = self.esn.data.get("esn") if isinstance(self.esn.data, dict) else self.esn.data
|
||||
cached_type = self.esn.data.get("type") if isinstance(self.esn.data, dict) else None
|
||||
if cached_esn != esn or cached_type != DeviceTypes.ANDROID or (hasattr(self.esn, "expired") and self.esn.expired):
|
||||
self.esn.set(esn_value, expiration=1 * 60 * 60)
|
||||
cache_expired = hasattr(self.esn, "expired") and self.esn.expired
|
||||
randomchar_pattern = r"\{randomchar_(\d+)\}"
|
||||
|
||||
if re.search(randomchar_pattern, esn_template):
|
||||
esn_regex = "^" + re.sub(
|
||||
r"\\\{randomchar_(\d+)\\\}",
|
||||
lambda match: rf"[A-Z0-9]{{{match.group(1)}}}",
|
||||
re.escape(esn_template)
|
||||
) + "$"
|
||||
|
||||
if cached_type == DeviceTypes.ANDROID and isinstance(cached_esn, str) and re.match(esn_regex, cached_esn) and not cache_expired:
|
||||
esn = cached_esn
|
||||
else:
|
||||
self.log.info("Generating Android ESN from configured randomchar template")
|
||||
esn = re.sub(
|
||||
randomchar_pattern,
|
||||
lambda match: "".join(random.choice("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") for _ in range(int(match.group(1)))),
|
||||
esn_template
|
||||
)
|
||||
self.esn.set({
|
||||
'esn': esn,
|
||||
'type': self.cdm.device_type
|
||||
}, expiration=1 * 60 * 60)
|
||||
else:
|
||||
esn = esn_template
|
||||
esn_value = {
|
||||
'esn': esn,
|
||||
'type': self.cdm.device_type
|
||||
}
|
||||
if cached_esn != esn or cached_type != DeviceTypes.ANDROID or cache_expired:
|
||||
self.esn.set(esn_value, expiration=1 * 60 * 60)
|
||||
else:
|
||||
ESN_GEN = "".join(random.choice("0123456789ABCDEF") for _ in range(30))
|
||||
generated_esn = f"NFCDIE-03-{ESN_GEN}"
|
||||
|
||||
@@ -22,7 +22,7 @@ esn_map:
|
||||
8131: "HISETVK84500000000000000000000000007401422"
|
||||
22590: "NFANDROID1-PXA-P-L3-XIAOMM2102J20SG-22590-020NTB086HJPGG70MDDMR0306MR0NNO5G3DJGFCKS9HJF58ER9QA21VFG4I0246JRN6TF16L9I627EPK708SH42UUMG1ASFVG20F3"
|
||||
12063: "NFANDROID1-PRV-P-SHENZHENKTC-49B1U-12063-2PAENERYJWY35H7F24163TMUCBBA4VRHQ2XZX4OBU4MUTKYFW50BMFBVGTUMN6IM0"
|
||||
7110: "NFANDROID1-PRV-P-MSD6886602GUHDANDROIDTV-HISENHISMARTTV-A4-7110-5EAE417AE3DB234B5FFC4EFC289A1B11D4475CC5949186C83F4C3D20FF203972"
|
||||
7110: "NFANDROID1-PRV-P-MSD6886602GUHDANDROIDTV-HISENHISMARTTV-A4-7110-{randomchar_64}"
|
||||
16401: "NFANDROID1-PRV-P-MSD6886602GUHDANDROIDTV-HISENHISMARTTV-A4-16401-FA2CF15C2E3A00BDDC3B6811C210893F0CD2C062471A62C2A0DD8C28BAE8DF42"
|
||||
endpoints:
|
||||
website: "https://www.netflix.com/nq/website/memberapi/{build_id}/pathEvaluator"
|
||||
|
||||
Reference in New Issue
Block a user