from PySide2.QtCore import QTimer, QTime, QDateTime
from PySide2.QtWidgets import QApplication, QMessageBox
from PySide2.QtUiTools import QUiLoader
from main import PackNameOperate, Log, wifi_adb_connect, Devices, input_text,LogcatManager,capture_screenshot
import os, sys
import subprocess
dev = Devices()
log=LogcatManager('D:/jb/logcat')
def processPath(path):
'''
:param path: 相对于根目录的路径
:return: 拼接好的路径
'''
if getattr(sys, 'frozen', False): # 判断是否存在属性frozen,以此判断是打包的程序还是源代码。false为默认值,即没有frozen属性时返回false
base_path = sys._MEIPASS # 该属性也是打包程序才会有,源代码尝试获取该属性会报错
else:
base_path = os.path.abspath(".") # 当源代码运行时使用该路径
return os.path.join(base_path, path)
txt=r'''1、日志保存路径'D:\jb\logcat',截图保存路径'D:\jb\tu',路径不存在会自动创建
2、应用切换功能是输入2个包名,点一下按钮可以切换到其中一个,在点一下就是切到另一个,如此循环
3、开启wifi adb是新开一个tcpip端口进行wifiadb连接,开启成功后马上拔掉adb线,不然这个wifiadb会被干掉,当然也可以在点一次
4、如果按钮啥的不起作用,可以看看是不是设备离线了,把adb线拔了在插上就可以了,按钮被禁用是检查到没有设备连接而不是设备离线
。 ゚゚・。・゚゚。
゚。 。゚
゚・。・゚
︵ ︵
( ╲ / /
╲ ╲/ /
╲ ╲ /
╭ ͡ ╲ ╲
╭ ͡ ╲ ╲ ノ
╭ ͡ ╲ ╲ ╱
╲
'''
class Stats:
def __init__(self):
self.kill_list = ['获取当前运行的包名','杀掉当前启动的app',
'清除当前app缓存信息', '清楚缓存并且杀掉app', '清楚缓存并且杀掉app并且重新启动']
self.ui = QUiLoader().load(processPath('adb.ui'))
# 下拉框添加内容
self.ui.kill_apps.addItems(self.kill_list)
# 按钮点击事件
self.ui.qd_app.clicked.connect(self.qd)
self.ui.zx.clicked.connect(self.kill)
self.ui.get_log.clicked.connect(self.log)
self.ui.disable.clicked.connect(self.wifi_disable)
self.ui.enable.clicked.connect(self.wifi_enable)
self.ui.bk.clicked.connect(self.bluetooth_enable)
self.ui.bg.clicked.connect(self.bluetooth_disable)
self.ui.huqie.clicked.connect(self.hq)
self.ui.wifi_adb.clicked.connect(self.wifi_adb_)
self.ui.write_in.clicked.connect(self.text_write_in)
self.ui.get_device.clicked.connect(self.devices)
self.ui.suoyou.clicked.connect(self.suoyou_log)
self.ui.dell.clicked.connect(self.del_log)
self.ui.time.clicked.connect(self.yl)
self.ui.jt.clicked.connect(self.jietu)
self.timer1 = QTimer()
self.timer1.setInterval(5000) # 设置定时器1的触发间隔为3秒
self.timer1.timeout.connect(self.devices)
self.timer1.start()
self.devices()
self.timer2 = QTimer()
self.timer2.setInterval(1000) # 设置定时器2的触发间隔为1秒
self.timer2.timeout.connect(self.update_button_text)
self.timer2.start()
self.update_button_text() # 初始
self.ui.ttt.setPlainText(txt)
def update_button_text(self):
current_datetime = QDateTime.currentDateTime()
time_text = current_datetime.toString('yyyy-MM-dd dddd hh:mm:ss')
self.ui.time.setText(time_text)
def check_adb_connection(self, d):
'''控制按钮是否都可用'''
buttons = [
self.ui.qd_app,
self.ui.zx,
self.ui.get_log,
self.ui.disable,
self.ui.enable,
self.ui.bk,
self.ui.bg,
self.ui.huqie,
self.ui.wifi_adb,
self.ui.write_in,
self.ui.get_device,
self.ui.suoyou,
self.ui.dell,
self.ui.time,
self.ui.jt
]
for button in buttons:
button.setEnabled(d)
def qd(self):
'''app根据包名启动'''
pack_name = self.ui.pack_name.text()
if PackNameOperate.pack_name_start(pack_name) == 1:
QMessageBox.critical(self.ui, '包名错误', '请检查包名是否输入正确!')
else:
QMessageBox.information(self.ui, '操作成功', f'{pack_name}启动完成')
# QMessageBox.close()
def kill(self):
'''app杀后台,清除缓存,启动等组合操作'''
xz = self.ui.kill_apps.currentText()
index = self.kill_list.index(xz)
if PackNameOperate.kill_app(index) == 0:
QMessageBox.information(self.ui, '操作成功', f'"{xz}"执行完成')
elif '包名' in PackNameOperate.kill_app(index):
QMessageBox.information(self.ui, '操作成功', PackNameOperate.kill_app(index))
else:
QMessageBox.critical(self.ui, '错误', '设备未连接或者未启动adb模式')
def log(self):
'''抓日志'''
Log.test()
def wifi_enable(self):
subprocess.getoutput('adb shell svc wifi enable')
QMessageBox.information(self.ui, '操作成功', f'wifi已打开')
def wifi_disable(self):
subprocess.getoutput('adb shell svc wifi disable')
QMessageBox.information(self.ui, '操作成功', f'wifi已关闭')
def bluetooth_enable(self):
subprocess.getoutput('adb shell svc bluetooth enable')
QMessageBox.information(self.ui, '操作成功', f'帅哥蓝牙已打开')
def bluetooth_disable(self):
subprocess.getoutput('adb shell svc bluetooth disable')
QMessageBox.information(self.ui, '操作成功', f'蓝牙已关闭')
def wifi_adb_(self):
ml = wifi_adb_connect()
if ml[0]==0:
QMessageBox.information(self.ui, '操作成功', f'已经连接wifiadb成功,命令为:{ml[1]},请3s内拔掉adb线')
else:
QMessageBox.information(self.ui, '操作失败', f'开启失败,命令为:{ml[1]},未获取到ip信息,检查是否处于同一个wifi')
def text_write_in(self):
text = self.ui.text.text()
input_text(text)
# subprocess.run(['adb', 'shell', 'input', 'text', text])
QMessageBox.information(self.ui, '操作成功', '写入完成')
def jietu(self):
capture_screenshot()
QMessageBox.information(self.ui, '操作成功', '截图成功')
def devices(self):
d = dev.dev_id()
'''获取当前连接的设备id'''
if d[0] == 0:
devices_info = d[1]
self.check_adb_connection(True)
elif d[0] == 00:
devices_info = d[1]
self.check_adb_connection(True)
else:
devices_info = d[1]
self.check_adb_connection(False)
self.ui.device.setText(str(devices_info))
def suoyou_log(self):
log.save_logcat()
QMessageBox.information(self.ui, '操作成功', '日志导出完成')
def del_log(self):
log.clear_logcat()
QMessageBox.information(self.ui, '操作成功', '日志清除完成')
def yl(self):
QMessageBox.information(self.ui, '嘿嘿', '要天天开心呀')
def hq(self):
'''2个应用互切'''
pack_1 = self.ui.pack1.text()
pack_2 = self.ui.pack2.text()
print(pack_1, pack_2)
if pack_1 == '':
QMessageBox.information(self.ui, '操作失败', '包名1填下,谢谢')
elif pack_2 == '':
QMessageBox.information(self.ui, '操作失败', '包名2填下,谢谢')
elif PackNameOperate.huqie(pack_1, pack_2) == 11:
QMessageBox.information(self.ui, '操作失败', f'找不到{pack_1}这个包')
elif PackNameOperate.huqie(pack_1, pack_2) == 12:
QMessageBox.information(self.ui, '操作失败', f'找不到{pack_2}这个包')
elif PackNameOperate.huqie(pack_1, pack_2) == 1:
QMessageBox.information(self.ui, '操作失败', '当前运行的应用不是输入自定义的2个互切应用')
elif pack_1 == pack_2:
QMessageBox.information(self.ui, '操作成功', '一个包写2遍没太大必要啊')
else:
QMessageBox.information(self.ui, '操作成功', '切换完成')
app = QApplication([])
stats = Stats()
stats.ui.show()
app.exec_()
import os
import re
import shutil
import subprocess
import time
from time import sleep
import datetime
class PackNameOperate():
@classmethod
def pack_name_start(cls, pack_name):
'''根据包名启动app'''
output = subprocess.getoutput(f'adb shell monkey -p {pack_name} --throttle 1 -s 2 -v -v -v 1')
if 'No activities found to run, monkey aborted' in output:
print('车机不存在该包名,请检查包名是否输入正确')
return 1
else:
return 0
@classmethod
def kill_app(cls, l):
'''
:param l: 0不输入是获取当前运行的包名,1是杀掉当前启动的app,2是清除当前app缓存信息,3是清楚缓存并且杀掉app,4是根据上一个前三个操作的包名启动app
:return:
'''
output = subprocess.getoutput('adb shell dumpsys window | findstr mCurrentFocus')
if not output == '':
try:
pack_name = 'com.' + re.findall(r'com.(.*?)/com', output)[0]
except:
pack_name = 'com.' + re.findall(r'com.(.*?)/io', output)[0]
if l == 0:
print(f'当前运行的包名是{pack_name}')
return f'当前运行的包名是{pack_name}'
if l == 1:
subprocess.getoutput(f'adb shell am force-stop {pack_name}')
print(f'包名为{pack_name}的app已经杀掉')
elif l == 2:
subprocess.getoutput(f'adb shell pm clear {pack_name}')
print(f'包名为{pack_name}的app缓存清楚成功')
elif l == 3:
subprocess.getoutput(f'adb shell pm clear {pack_name}')
subprocess.getoutput(f'adb shell am force-stop {pack_name}')
print(f'包名为{pack_name}的app清楚缓存并且杀掉成功')
elif l == 4:
subprocess.getoutput(f'adb shell pm clear {pack_name}')
subprocess.getoutput(f'adb shell am force-stop {pack_name}')
cls.pack_name_start(pack_name)
print(f'包名为{pack_name}的app清楚缓存并且杀掉成功')
print(f'{pack_name}重新启动完成')
return 0
print('设备未连接或者未启动adb模式')
return 1
@classmethod
def get_pack_name(cls):
output = subprocess.getoutput('adb shell dumpsys window | findstr mCurrentFocus')
try:
pack_name = 'com.' + re.findall(r'com.(.*?)/com', output)[0]
except:
pack_name = 'com.' + re.findall(r'com.(.*?)/io', output)[0]
# print(f'当前运行的包名是{pack_name}')
return pack_name
@classmethod
def huqie(cls, pack1, pack2):
a = cls.get_pack_name()
print(f'当前在运行的包名{a}')
if a == pack1:
if cls.pack_name_start(pack2) == 1:
# 说明包名不对
return 12
elif a == pack2:
if cls.pack_name_start(pack1) == 1:
return 11
else:
print('当前运行的应用不输入自定义的2个互切应用')
return 1
class Log():
@classmethod
def test(cls):
for i in range(4):
sleep(0.3)
print(f'控制台打印{i}')
# @classmethod
# def move_file(cls, besave_dir=ys__log_path, fm='zip'):
# """
# 将文件夹压缩成指定格式的压缩包
# :param besave_dir: 压缩文件夹的目录 如 ---r"D:\log_dir"
# :param format: 压缩的格式:"zip", "tar", "gztar","bztar", "xztar"
# :return:
# """
# if os.path.exists(besave_dir):
# zip_name = shutil.make_archive(besave_dir, f'{fm}', besave_dir)
# print(zip_name) # 返回文件的最终路径
#
# @classmethod
# def del_dir(cls, dir_path=pc_log_path):
# '''删除目录下所有文件'''
# for filename in os.listdir(dir_path):
# file_path = os.path.join(dir_path, filename)
# if os.path.isfile(file_path) or os.path.islink(file_path):
# os.unlink(file_path)
# elif os.path.isdir(file_path):
# shutil.rmtree(file_path)
#
# @classmethod
# def log(cls):
# cls.del_dir()
# subprocess.getoutput(f'adb pull {cj_log_path} {pc_log_path}')
# cls.move_file()
# Log.test()
def wifi_adb_connect():
def get_car_wifi_ip():
process = subprocess.run(['adb', 'shell', 'ifconfig', 'wlan0'], capture_output=True, text=True)
output = process.stdout.strip()
ip_line = [line for line in output.split('\n') if 'inet addr' in line]
if len(ip_line) > 0:
ip = ip_line[0].split()[1].split(':')[1]
subprocess.run(['adb', 'tcpip', '6666'])
print(f'端口号6666')
return ip
else:
return None
# 使用示例:获取车机的WiFi IP
car_wifi_ip = get_car_wifi_ip()
print(car_wifi_ip)
# ip = car_wifi_ip
subprocess.run(['adb', 'disconnect'])
subprocess.run(['adb', 'connect', f'{car_wifi_ip}:6666'])
# 获取连接状态输出
result = subprocess.run(['adb', 'devices'], capture_output=True, text=True)
output = result.stdout.strip().encode('utf-8').decode('gbk')
print(output)
if '不知道这样的主机' in output:
return 1,output
else:
return 0, f'adb connect {car_wifi_ip}:6666'
class Devices:
def check_adb_connection(self):
try:
# 检查连接状态
command = 'adb devices'
output = subprocess.check_output(command.split()).decode().strip()
# 检查输出结果中是否包含设备列表
if 'List of devices attached' in output:
# 提取设备列表
devices = output.split('\n')[1:]
# 检查设备列表是否为空
if len(devices) > 0:
# 提取所有设备的设备ID
device_ids = [device.split('\t')[0] for device in devices]
return device_ids
else:
return None
else:
return None
except subprocess.CalledProcessError:
return None
def dev_id(self):
device_ids = self.check_adb_connection()
# if 'offline' in subprocess.getoutput(f'adb shell'):
# subprocess.run(['adb', 'kill-server'])
# time.sleep(1)
# subprocess.run(['adb', 'start-server'])
# print('检测到设备离线,重启adb服务解决中')
if device_ids is not None:
if len(device_ids) == 1:
# print(f"设备ID: {device_ids[0]}")
return 0, f"设备ID: {device_ids[0]}"
elif len(device_ids) > 1 :
# 清除所有连接
subprocess.run(['adb', 'disconnect'])
# print(f'干掉了{device_ids[1:]}等设备')
return 00, f"设备ID: {device_ids[0]},干掉了{device_ids[1:]}等设备"
else:
return 1
else:
# print("ADB未成功连接到任何设备")
return 1, "ADB未成功连接到任何设备,按钮全部禁用"
def input_text(text):
# 转义特殊字符
text = text.replace('\\', '\\\\').replace('"', '\\"')
# 执行 adb shell input text 命令
subprocess.run(['adb', 'shell', 'input', 'text', f'"{text}"'])
class LogcatManager:
def __init__(self, save_directory):
self.save_directory = save_directory
def _get_device_info(self):
# 获取设备的Android版本
android_version_cmd = ['adb', 'shell', 'getprop', 'ro.build.version.release']
android_version_process = subprocess.Popen(android_version_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
android_version_output, _ = android_version_process.communicate()
android_version = android_version_output.strip()
# 获取屏幕分辨率
screen_resolution_cmd = ['adb', 'shell', 'wm', 'size']
screen_resolution_process = subprocess.Popen(screen_resolution_cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, universal_newlines=True)
screen_resolution_output, _ = screen_resolution_process.communicate()
screen_resolution = screen_resolution_output.strip().split()[2]
# 获取系统版本信息
system_info_cmd = ['adb', 'shell', 'getprop', 'ro.build.description']
system_info_process = subprocess.Popen(system_info_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
system_info_output, _ = system_info_process.communicate()
system_info = system_info_output.strip()
return android_version, screen_resolution, system_info
def _create_directory(self, directory):
if not os.path.exists(directory):
os.makedirs(directory)
def _get_current_time(self):
return datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')
def _build_file_name(self, android_version, screen_resolution, system_info):
current_time = self._get_current_time()
file_name = f'{current_time}.Android{android_version}.{screen_resolution}.{system_info}.logcat.txt'
return file_name
def _build_file_path(self, file_name):
file_path = os.path.join(self.save_directory, file_name)
return file_path
def _export_logcat(self, file_path):
# 执行 adb logcat -d 命令,导出日志到文件
cmd = ['adb', 'logcat', '-d']
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 检查目录是否存在,如果不存在则创建目录
self._create_directory(self.save_directory)
try:
with open(file_path, 'wb') as file:
for line in process.stdout:
file.write(line)
print(f'Logcat已成功导出到文件:{file_path}')
except Exception as e:
print(f'保存Logcat文件时发生错误:{e}')
def save_logcat(self):
# 获取设备信息
android_version, screen_resolution, system_info = self._get_device_info()
# 构建文件名
file_name = self._build_file_name(android_version, screen_resolution, system_info)
# 构建完整的文件路径
file_path = self._build_file_path(file_name)
# 导出Logcat并保存到文件
self._export_logcat(file_path)
# return 'Logcat已成功导出成功'
#
# def save_realtime_logcat(self):
# # 获取设备信息
# android_version, screen_resolution, system_info = self._get_device_info()
#
# # 构建文件名
# file_name = self._build_file_name(android_version, screen_resolution, system_info)
#
# # 构建完整的文件路径
# file_path = self._build_file_path(file_name)
# # 执行 adb logcat 命令,实时保存日志到文件
# cmd = ['adb', 'logcat']
# print(f'实时保存的Logcat已成功保存到文件:{file_path}')
# with open(file_path, 'w') as file:
# process = subprocess.Popen(cmd, stdout=file, stderr=subprocess.PIPE, universal_newlines=True)
# try:
# process.wait()
# except KeyboardInterrupt:
# process.terminate()
def clear_logcat(self):
# 执行 adb shell logcat -c 命令,清除Logcat日志
cmd = ['adb', 'shell', 'logcat', '-c']
subprocess.run(cmd)
print('Logcat日志已清除')
# return 'Logcat日志已清除'
def capture_screenshot():
from datetime import datetime
# 获取当前时间并格式化为字符串
current_time = datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
# 创建目录
directory = "D:/jb/tu/"
os.makedirs(directory, exist_ok=True)
# 执行ADB命令进行截图
subprocess.run(["adb", "shell", "screencap", "-p", "/sdcard/screenshot.png"])
# 将截图文件复制到本地目录
local_path = os.path.join(directory, f"{current_time}.png")
subprocess.run(["adb", "pull", "/sdcard/screenshot.png", local_path])
return 0
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['gui.py'],
pathex=[],
binaries=[],
datas=[('adb.ui','.')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='shy',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['i.ico'],
)
是qt设计师生成的ui界面,设置属性配合代码操作
<ui version="4.0">
<class>adb_shellclass>
<widget class="QWidget" name="adb_shell">
<property name="geometry">
<rect>
<x>0x>
<y>0y>
<width>768width>
<height>564height>
rect>
property>
<property name="windowTitle">
<string>安卓测试操作string>
property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QPushButton" name="time">
<property name="text">
<string>时间string>
property>
widget>
item>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0number>
property>
<widget class="QWidget" name="widget">
<property name="minimumSize">
<size>
<width>0width>
<height>18height>
size>
property>
<attribute name="title">
<string>常用操作string>
attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>根据包名操作string>
property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="pack_name">
<property name="placeholderText">
<string>请输入app包名string>
property>
widget>
item>
<item>
<widget class="QPushButton" name="qd_app">
<property name="text">
<string>启动appstring>
property>
widget>
item>
layout>
item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QComboBox" name="kill_apps"/>
item>
<item>
<widget class="QPushButton" name="zx">
<property name="text">
<string>执行string>
property>
widget>
item>
layout>
item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="pack1">
<property name="placeholderText">
<string>包名1string>
property>
widget>
item>
<item>
<widget class="QLineEdit" name="pack2">
<property name="placeholderText">
<string>包名2string>
property>
widget>
item>
<item>
<widget class="QPushButton" name="huqie">
<property name="text">
<string>应用切换string>
property>
widget>
item>
layout>
item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>系统控制string>
property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="wifi_adb">
<property name="text">
<string>开启wifiadbstring>
property>
widget>
item>
<item>
<widget class="QPushButton" name="enable">
<property name="text">
<string>wifi打开string>
property>
widget>
item>
<item>
<widget class="QPushButton" name="disable">
<property name="text">
<string>wifi关闭string>
property>
widget>
item>
<item>
<widget class="QPushButton" name="bk">
<property name="text">
<string>蓝牙打开string>
property>
widget>
item>
<item>
<widget class="QPushButton" name="bg">
<property name="text">
<string>蓝牙关闭string>
property>
widget>
item>
layout>
item>
layout>
widget>
item>
<item>
<widget class="QLineEdit" name="text"/>
item>
<item>
<widget class="QPushButton" name="write_in">
<property name="text">
<string>开始写入文本(不支持中文)string>
property>
widget>
item>
<item>
<widget class="QLineEdit" name="device">
<property name="text">
<string/>
property>
widget>
item>
<item>
<widget class="QPushButton" name="get_device">
<property name="text">
<string>查询当前连接的设备(5s自动查询一次)string>
property>
widget>
item>
layout>
widget>
item>
layout>
widget>
<widget class="QWidget" name="tab_6">
<attribute name="title">
<string>日志操作和使用说明string>
attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QPushButton" name="jt">
<property name="text">
<string>截图string>
property>
widget>
item>
<item>
<widget class="QPushButton" name="dell">
<property name="text">
<string>清除logcatstring>
property>
widget>
item>
<item>
<widget class="QPushButton" name="suoyou">
<property name="text">
<string>抓取从现在到之前的所有logcatstring>
property>
widget>
item>
<item>
<widget class="QPushButton" name="get_log">
<property name="text">
<string>控制台打印测试string>
property>
<property name="iconSize">
<size>
<width>10width>
<height>10height>
size>
property>
widget>
item>
layout>
item>
<item>
<widget class="QPlainTextEdit" name="ttt">
<property name="readOnly">
<bool>truebool>
property>
widget>
item>
layout>
item>
layout>
widget>
widget>
item>
layout>
widget>
<resources/>
<connections/>
ui>
https://blog.csdn.net/aaaaaaaaanjjj/article/details/134157127