2024-8-28-suno自动批量制作音乐

去年年底试过suno自动作曲,我忘记了为什么当时没试用下去,可能那时还不支持歌词?前两天也不知道为啥想起来去摸这玩意儿,可能是在youtube听那些lofi集合实在是恶心,搞来搞去就那么点东西,自己的歌单也很有限。最近一直借用人工智能弄自动化,看到suno每天支持做5x2首歌(歌词相同版)于是我想挑战下用ai驱动开多账号来为自己生产歌单。当然这个想法不是纯粹想要苦行僧一样的挑战或是炫技,而是因为我大概用了一晚上在suno本身有600多积分的情况下,一次做歌是10积分,我一口气几乎都用完了,好像不是一晚而是1晚再加1天?总之在这个过程中,我生产了几首我觉得很不错的音乐,是那种我愿意反复循环的,我当时甚至是想付费来生产的。我的想法是如果每100首能产生2-3个好听的歌曲,那么买10000首就可以有200-300个了,这其实和midjourney暴力穷举筛选各种雕塑、景观、外立面设计一样就是设法用控制变量手法提高产出效率,当然前提是要量大管饱。

上来先是假设在登录状态,第一个碰到的难题是被suno识别出电脑操控,稍微搜了下发现undetected chrome这个python包可以脱离chrome driver使用,不过使用时会有打开网页失败的概率,我一开始把创作歌曲和下载分成两个部分来做,在测试程序的过程中多次打不开浏览器,最后居然手动都打不开了,这个问题折腾了我大概有1个小时,后来通过删除user data下的default文件夹,重开浏览器成功了,同时之前的各种网站的登录状态以及收藏夹、历史记录啥的都没了。

创作歌曲部分就是对三个输入框填充数据,歌词、风格、标题,没有标题么也是可以生产歌曲的我一开始每天好像。老套路,用chatgpt、文心一言解析,把输入框和create按钮的xpath提取出来,然后就是歌词和风格,这个和midjourney的3x排列组合添加txt读行以及kimi总结章节遍历文件夹的txt是一回事,好像我都没有让chatgpt借鉴那两个程序就顺利过了。

下载部分卡了我一晚上,suno的下载是一个“点击更多”后,需要通过鼠标移动到位展开的子菜单。我按着chatgpt的各种方法从点击download菜单引出子菜单到moveto,然后再到moveto子菜单,用javascript控制移动位置全部失败,真是让人万念俱灰了。最后是通过moveto子菜单然后用sendkeys enter键实现了下载,之前那些方法为啥不行不清楚也不深究了。

这两个部分的程序搞了一天,然后第二天早上想搞自动登录退出,我注册了appleid、discord和google账号相同算在discord上,google又注册了一个,顺带一提我用telegram的gmail bot来接收管理google新注册账号的邮箱,还有microsoft一个号,除了appleid需要每次输入密码,其他三个号都是点击就能进。然而在selenium配合undetected chrome下,过不了suno的登录验证,它用到了cloudflare网上初步查了下好像蛮复杂的,我想暂时就放一下了。

然后是两个程序的整合,稍微遇到了些小麻烦,chatgpt在某些时候会因为输出长度而没法提供过长程序的完整版,好像和本次会话的长度也有关系,新开一个搞会顺利些。接下来的问题是控制变量了,我一开始的设定是,chinese1,chinese2,foreign1,foreign2,lyrical,orcherstra,emotion,7个变量会导致每个变量稍微多几个成员就会有庞大的组合,歌词反复重复。而且这样搞很复杂,我的思路是让百度文心一言给我把中文版歌词翻译成多语言,通过正则去判断语言种类提取到各自txt再把中外文分配整合。这种模式下我大概尝试了两天,但产出率约等于0,这两天的尝试都是阿拉伯语,会不会是阿拉伯语不适合歌曲?我开始有这种疑惑,后来我换了个思路,直接让文心一言创作中外文结合的歌曲不就得了,我设置了起始结束的标志提取当中的文本即歌词。但是效果好像也不行,于是我推测大概是文心一言不擅长外文歌词创作,这需要chatgpt来搞,于是我想把这个程序快速套到chatgpt身上,结果失败了chatgpt和suno一样有cloudflare验证,看来是躲不过去,必须啃一下这块硬骨头。我看到网上好几种说法,首先undetected chrome不行,它过了suno 创作下载的验证但是登录的cloudflare实测失败了。然后我试了国产的python 包,drissionpage通过了cloudflare,成功让我在登录状态中进入chatgpt,然而drissionpage和selenium用法不同,需要对选取元素部分的代码重写,可能因为是刚刚出来的新东西,所以chatgpt并不能帮忙做这部分的修改,没办法只能自己去官网看文档修改,最终成功征服了自动控制chatgpt批量生产歌词,换而言之也就是可以通过txt读行排列组合的方式用标识符控制chatgpt做任何解析工作。

在后两天的测试中,我发现用chatgpt生成的歌词显著提高了歌曲产出率,两天里拿下了至少6首歌。

2024-9-3更新:

做了些小修改使标题包含style中的emotion,lyricals,orchestral变量作为提示词,其实还得把female voice, anime这些style中包含的固定关键词也包含进去,这样就能确保以后歌曲多了能够一眼看出来这首当时用了哪些style提示词,可以分类控制变量比较生成的歌曲。

suno批量制作音乐并下载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
  

import logging
from selenium.webdriver.chrome.service import Service
import schedule
import random
import time
import os
from datetime import datetime
import pickle
from itertools import product
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
import undetected_chromedriver as uc
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
import sys

# 配置
foreign1_dir = "E:/suno/MergeLyric"
foreign2_dir = "E:/suno/null"
lyrical_file = "E:/suno/musicstyle/Lyrical.txt"
emotion_file = "E:/suno/musicstyle/Emotion.txt"
orchestral_file = "E:/suno/musicstyle/Orchestral.txt"
chinese1_file = "E:/suno/null/null.txt"
chinese2_file = "E:/suno/null/null.txt"
state_file = "task_state.pkl"

# 设置日志
log_filename = f"{datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}.txt"
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[
logging.FileHandler(log_filename, 'w', 'utf-8'),
logging.StreamHandler(sys.stdout)
])

# Selenium配置
options = Options()
options.add_argument('lang=zh_CN.UTF-8')
options.add_argument('--ignore-certificate-errors')
options.add_argument('--ignore-ssl-errors')
options.add_argument('user-agent="Mozilla/5.0 (iPod; U; CPU iPhone OS 2_1 like Mac OS X; ja-jp) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5F137 Safari/525.20"')
options.add_argument(r'--user-data-dir=C:/Users/A/AppData/Local/Google/Chrome/User Data')
driver = uc.Chrome(options=options)

url = 'https://suno.com/create'
driver.get(url)
time.sleep(5)

# 全局变量
combinations = []
task_count = 0
songtitle = 557
tasks_since_last_pause = 0
total_tasks = 0

def get_current_time():
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

def read_foreign_content(directory):
content_list = []
for filename in os.listdir(directory):
if filename.endswith(".txt"):
with open(os.path.join(directory, filename), 'r', encoding='utf-8') as file:
content = file.read().strip()
content_list.append(content)
logging.info(f"已读取 {len(content_list)} 个文件的内容来自 {directory}。")
return content_lis

def read_lines(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
lines = [line.strip() for line in file.readlines()]
logging.info(f"已读取 {len(lines)} 行内容来自 {file_path}。")
return lines

def read_whole_file(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
content = file.read().strip()
logging.info(f"已读取文件内容来自 {file_path}。")
return content

def generate_combinations():
global combinations
foreign1_contents = read_foreign_content(foreign1_dir)
foreign2_contents = read_foreign_content(foreign2_dir)
lyrical_lines = read_lines(lyrical_file)
emotion_lines = read_lines(emotion_file)
orchestral_lines = read_lines(orchestral_file)
chinese1_content = read_whole_file(chinese1_file)
chinese2_content = read_whole_file(chinese2_file)

combinations = list(product(foreign1_contents, foreign2_contents, lyrical_lines, emotion_lines, orchestral_lines, [chinese1_content], [chinese2_content]))
logging.info(f"已生成 {len(combinations)} 个组合。")

def save_state():
with open(state_file, 'wb') as file:
pickle.dump((combinations, task_count, songtitle), file)
logging.info("任务状态已保存。")

def load_state():
global combinations, task_count, songtitle
if os.path.exists(state_file):
with open(state_file, 'rb') as file:
combinations, task_count, songtitle = pickle.load(file)
logging.info("恢复已保存的任务状态。")
else:
generate_combinations()

def perform_web_interaction(chinese1, foreign1, chinese2, foreign2, emotion, lyrical, orchestral):
try:
# 标题格式为 songtitle + emotion + lyrical + orchestral
title = f"{songtitle}_{emotion}_{lyrical}_{orchestral}"

input_box_title = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, '//textarea[@placeholder="Enter a title"]'))
)
input_box_title.clear()
input_box_title.send_keys(title)

input_box1 = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, '//textarea[@placeholder="Enter your own lyrics or describe a song and click Write About..."]'))
)
input_box1.clear()

# 插入打乱顺序后的内容
input_box1.send_keys(f"{foreign1}")


input_box2 = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, '//textarea[@placeholder="Enter style of music"]'))
)
input_box2.clear()
input_box2.send_keys(f"female vocal , {orchestral} , anime , {emotion} , {lyrical} ")

submit_button = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, "//button[.//span[text()='Create']]"))
)
submit_button.click()
time.sleep(2)

except Exception as e:
logging.error(f"Error during web interaction: {e}")

def download_music():
try:
# 找到所有包含音乐标题的 <span> 元素
spans = driver.find_elements(By.CSS_SELECTOR, "span[title]")

# 过滤出 title 属性的数字前缀部分并进行排序
valid_spans = []
for span in spans:
title = span.get_attribute("title")
# 提取标题前缀中的数字部分
numeric_prefix = ''.join(filter(str.isdigit, title.split()[0]))
if numeric_prefix.isdigit(): # 确保 title 前缀是数字
valid_spans.append((span, int(numeric_prefix)))

# 根据数字前缀进行降序排序
sorted_spans = sorted(valid_spans, key=lambda x: x[1], reverse=True)

# 提取前10个
top_10_spans = sorted_spans[:10]

# 打印提取到的音乐标题
logging.info("即将下载的音乐:")
for span, _ in top_10_spans:
logging.info(span.get_attribute("title"))

for span, _ in top_10_spans:
# 找到父级元素,确保找到对应的“更多操作”按钮
parent_element = span.find_element(By.XPATH, "./../../..")

# 找到对应的“更多操作”按钮
button = parent_element.find_element(By.XPATH, ".//button[contains(@style, 'width: 32px; height: 32px;') and @type='button']")


# 点击按钮以触发“更多操作”菜单

button.click()

# 等待菜单加载
time.sleep(2)

# 定位“Download”选项
try:
download_option = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, "//*[text()='Download']"))
)

# 使用ActionChains来悬停在“Download”选项上
actions = ActionChains(driver)
actions.move_to_element(download_option).perform()

# 等待子菜单显示出来
time.sleep(2)

# 定位并点击“Audio”选项
audio_option = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, "//*[@data-testid='download-audio-menu-item']"))
)

actions = ActionChains(driver)
actions.move_to_element(download_option).perform()

# 等待子菜单显示出来
time.sleep(2)

# 使用回车键来触发下载
audio_option.send_keys(Keys.ENTER)
time.sleep(1) # 适当的延迟,确保第一次回车已完成
audio_option.send_keys(Keys.ENTER)

# 输出成功点击的音乐标题
logging.info(f"已成功下载音乐: {span.get_attribute('title')}")

except Exception as e:
logging.error(f"下载音乐 {span.get_attribute('title')}")

# 等待下载完成或稍作停留
time.sleep(10)

except Exception as e:
logging.error(f"Error during music download: {e}")


def task():
global combinations, task_count, songtitle, tasks_since_last_pause, total_tasks

if combinations and total_tasks < 5:
foreign1, foreign2, lyrical, emotion, orchestral, chinese1, chinese2 = combinations.pop(0)
task_count += 1
total_tasks += 1
songtitle += 1
logging.info(f"{get_current_time()} - 执行任务 {task_count}: songtitle = '{songtitle}', chinese1 = '{chinese1}', foreign1 = '{foreign1}', chinese2 = '{chinese2}', foreign2 = '{foreign2}', Emotion = '{emotion}', Lyrical = '{lyrical}', Orchestral = '{orchestral}'")

perform_web_interaction(chinese1, foreign1, chinese2, foreign2, emotion, lyrical, orchestral)

if total_tasks >= 5:
logging.info(f"{get_current_time()} - 已执行 5 次提交,等待 300 秒后开始下载。\n\n")
time.sleep(300)
download_music()
total_tasks = 0 # 重置任务计数器
logging.info(f"{get_current_time()} - 所有音乐下载完毕,等待 180 秒后结束程序。\n\n")
time.sleep(90)
save_state()
time.sleep(90)
sys.exit()
else:
logging.info(f"{get_current_time()} - 未找到更多任务组合,任务结束。")
save_state()
sys.exit()


load_state()
# 使用 schedule 每隔固定时间执行任务
job = schedule.every(2.6).minutes.do(task)


try:
while True:
schedule.run_pending()
time.sleep(1)
except KeyboardInterrupt:
save_state()
logging.info("程序已终止,状态已保存。")

2024-8-30-midjourney更换生产工具 2024-8-22-midjourney批量动物雕塑图片到unique3d转换3d雕塑

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×