audition.py
71.4 KB
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
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
import json
from django.core.mail import send_mail
from django.http import JsonResponse
from api.views import ResponseFactory,PageNumberPagination,createMessage,deleteMessage,pushSubscribeMessage,get_oss_file
from api import models,serializers
from HisinApi import settings
from django.utils import timezone
from api.views import upload_audio,auto_upload_audio, AuthPermissionRequired,get_user_info,ChangeAudio,WeChatApi,user_point_record,JPush,user_permission
import threading
from api import verification
from rest_framework.views import APIView
from django.utils.decorators import method_decorator
from django.db import transaction
from api import loggin
import librosa
import pyroomacoustics as pra
import pydub
import numpy as np
import time
import os
import random
import shutil
from math import log
from django.db.models import Q
from django_redis import get_redis_connection
from api.loggin import logger
import requests
sem = threading.Semaphore(4)
con = get_redis_connection("default")
# 板式混响
def plate_mixin(person_voice_path,result_file_path,mixin_ratio):
fs = 44100
room_dim = [18 * mixin_ratio, 15 * mixin_ratio] # 房间尺寸米
mic1_dim = [9 * mixin_ratio - 0.4, 7.5 * mixin_ratio, ] # 麦克风1位置
mic2_dim = [9 * mixin_ratio + 0.4, 7.5 * mixin_ratio] # 麦克风2位置
per_dim = [9 * mixin_ratio, 7.5 * mixin_ratio - 0.2] # 人声位置
scattering = 'rpg_qrd' # 散射模式,可选项 rpg_skyline ,rpg_qrd
max_order = 20 # 最大反射次数
absorption = False # 是否开启空气吸收
humidity = 0 # 空气湿度
room = pra.ShoeBox(room_dim, fs=fs,
materials=pra.Material(energy_absorption="hard_surface", scattering=scattering)
, max_order=max_order, air_absorption=absorption, humidity=humidity)
audio, _ = librosa.load(person_voice_path, sr=fs) # 导入一个单通道语音作为源信号 source signal
room.add_source(per_dim, signal=audio, delay=0)
mic_locs = np.c_[
mic1_dim, # mic 1
mic2_dim, # mic 2
]
room.add_microphone_array(mic_locs) # 最后将麦克风阵列放在房间里
room.compute_rir()
room.simulate(reference_mic=0)
room.mic_array.to_wav(result_file_path, norm=True, bitdepth=np.float32, )
# room混响
def room_mixin(person_voice_path,result_file_path):
mixin_ratio = 1
fs = 44100
rt60_tgt = 0.5
room_dim = [9*mixin_ratio, 7.5*mixin_ratio, 3.5*mixin_ratio]
e_absorption, max_order = pra.inverse_sabine(rt60_tgt, room_dim)
room = pra.ShoeBox(room_dim, fs=fs, materials=pra.Material(e_absorption), max_order=max_order)
audio, _ = librosa.load(person_voice_path, sr=fs)
room.add_source([6.3*mixin_ratio, 4.9*mixin_ratio, 1.2], signal=audio, delay=0.3)
mic_locs = np.c_[
[6.3*mixin_ratio, 4.87*mixin_ratio, 1.2], # mic 1
[6.3*mixin_ratio, 4.93*mixin_ratio, 1.2], # mic 2
]
room.add_microphone_array(mic_locs)
room.compute_rir()
room.simulate(reference_mic=0)
room.mic_array.to_wav(result_file_path, norm=True, bitdepth=np.float32, )
# room混响
def hall_mixin(person_voice_path, result_file_path):
mixin_ratio = 2
fs = 44100
rt60_tgt = 3
room_dim = [6 * mixin_ratio, 6 * mixin_ratio, 3.5]
e_absorption, max_order = pra.inverse_sabine(rt60_tgt, room_dim)
room = pra.ShoeBox(room_dim, fs=fs, materials=pra.Material(e_absorption), max_order=30)
audio, _ = librosa.load(person_voice_path, sr=fs)
room.add_source([3 * mixin_ratio, 3*mixin_ratio , 1.2], signal=audio, delay=0)
mic_locs = np.c_[
[3 * mixin_ratio, 2.95 * mixin_ratio, 1.2], # mic 1
[3 * mixin_ratio, 3.05 * mixin_ratio, 1.2], # mic 2
]
room.add_microphone_array(mic_locs)
room.compute_rir()
room.simulate(reference_mic=0)
room.mic_array.to_wav(result_file_path, norm=True, bitdepth=np.float32, )
def mixin(person_voice_path,person_volume,bg_audio_path,bg_volume, mixin_ratio,offset,mixin_pre_id,remove_path):
"""预览合成"""
with sem:
try:
t = str(int(time.time())) + str(random.randint(0, 10000000000))
os.mkdir("./api/static/{}".format(t))
base_path = "./api/static/{}".format(t)
mixin_output_path = base_path + '/mixin_out-{}.wav'.format(str(random.randint(0, 10000000000)))
out_path = base_path + '/compose_out.mp3'.format(str(random.randint(0, 10000000000)))
if mixin_ratio:
if mixin_ratio == 1:
room_mixin(person_voice_path, mixin_output_path)
elif mixin_ratio == 2:
plate_mixin(person_voice_path,mixin_output_path,1)
elif mixin_ratio == 3:
hall_mixin(person_voice_path,mixin_output_path)
compose(mixin_output_path,person_volume,bg_audio_path,bg_volume,offset,out_path,mixin_ratio)
else:
compose(person_voice_path, person_volume, bg_audio_path, bg_volume, offset, out_path,mixin_ratio)
with open(out_path, 'rb') as of:
file_data = of.read()
of.close()
demo_url = upload_audio(file_data)
# 删除零时文件
shutil.rmtree(remove_path)
shutil.rmtree(base_path)
#修改合成状态和demo
models.MixinPreviews.objects.filter(id=mixin_pre_id).update(url=demo_url, syn_status=1,updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"))
except:
models.MixinPreviews.objects.filter(id=mixin_pre_id).update(url='',syn_status=3,updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"))
def mixin_save(person_voice_path,person_volume,bg_audio_path,bg_volume, mixin_ratio,offset,ahu_id,remove_path):
"""保存合成"""
with sem:
try:
# 状态修改为合成中
models.ActivityHasUsers.objects.filter(id=ahu_id).update(syn_status=2, updated_at=timezone.now().strftime(
"%Y-%m-%d %H:%M:%S"))
t = str(int(time.time())) + str(random.randint(0, 10000000000))
os.mkdir("./api/static/{}".format(t))
base_path = "./api/static/{}".format(t)
mixin_output_path = base_path + '/mixin_out-{}.wav'.format(str(random.randint(0, 10000000000)))
out_path = base_path + '/compose_out.wav'.format(str(random.randint(0, 10000000000)))
if mixin_ratio:
if mixin_ratio == 1:
plate_mixin(person_voice_path,mixin_output_path,1)
elif mixin_ratio == 2:
room_mixin(person_voice_path,mixin_output_path)
elif mixin_ratio == 3:
hall_mixin(person_voice_path,mixin_output_path)
compose(mixin_output_path,person_volume,bg_audio_path,bg_volume,offset,out_path,mixin_ratio)
else:
compose(person_voice_path, person_volume, bg_audio_path, bg_volume, offset, out_path,mixin_ratio)
with open(out_path, 'rb') as of:
file_data = of.read()
of.close()
#获取时长
demo_music = pydub.AudioSegment.from_mp3(out_path)
duration = demo_music.duration_seconds
demo_url = upload_audio(file_data)
# 删除零时文件
shutil.rmtree(base_path)
shutil.rmtree(remove_path)
#保存至参与活动表中
models.ActivityHasUsers.objects.filter(id=ahu_id).update(demo_url=demo_url,durations=duration,syn_status=1,updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"))
except Exception as e:
models.ActivityHasUsers.objects.filter(id=ahu_id).update(demo_url='',syn_status=3,updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"))
def person_voice_mixin(person_voice_path,result_file_path,mixin_ratio):
fs = 44100
room_dim = [18 * mixin_ratio, 15 * mixin_ratio] # 房间尺寸米
mic1_dim = [9 * mixin_ratio - 0.4, 7.5 * mixin_ratio, ] # 麦克风1位置
mic2_dim = [9 * mixin_ratio + 0.4, 7.5 * mixin_ratio] # 麦克风2位置
per_dim = [9 * mixin_ratio, 7.5 * mixin_ratio - 0.2] # 人声位置
scattering = 'rpg_qrd' # 散射模式,可选项 rpg_skyline ,rpg_qrd
max_order = 10 # 最大反射次数
absorption = False # 是否开启空气吸收
humidity = 0 # 空气湿度
room = pra.ShoeBox(room_dim, fs=fs,
materials=pra.Material(energy_absorption="hard_surface", scattering=scattering)
, max_order=max_order, air_absorption=absorption, humidity=humidity)
audio, _ = librosa.load(person_voice_path, sr=fs) # 导入一个单通道语音作为源信号 source signal
room.add_source(per_dim, signal=audio, delay=0)
mic_locs = np.c_[
mic1_dim, # mic 1
mic2_dim, # mic 2
]
room.add_microphone_array(mic_locs) # 最后将麦克风阵列放在房间里
room.compute_rir()
room.simulate(reference_mic=0)
room.mic_array.to_wav(result_file_path, norm=True, bitdepth=np.float32, )
# 将伴奏和人声合成
def compose(person_voice_path,person_volume,bg_audio_path,bg_volume,offset,out_path,mixin_ratio):
if mixin_ratio :
per_sound = pydub.AudioSegment.from_wav(person_voice_path)
else:
per_sound = pydub.AudioSegment.from_mp3(person_voice_path)
audio_sound = pydub.AudioSegment.from_mp3(bg_audio_path)
audio_sound_length = audio_sound.duration_seconds * 1000
per_sound_length = per_sound.duration_seconds * 1000
if per_sound_length < audio_sound_length:
audio_sound = audio_sound[:int(per_sound_length)]
elif per_sound_length > audio_sound_length:
per_sound = per_sound[:int(audio_sound_length)]
per_dBFS = per_sound.dBFS
bg_dBFs = audio_sound.dBFS
per_radio = 10 ** (per_dBFS / 20)
bg_radio = 10 ** (bg_dBFs / 20)
to_per_radio = per_radio * person_volume
to_bg_radio = bg_radio * bg_volume
if to_per_radio == 0:
to_per_radio = 0.0001
if to_bg_radio == 0:
to_bg_radio = 0.0001
to_per_dbfs = 20 * log(to_per_radio, 10)
to_bg_dbfs = 20 * log(to_bg_radio, 10)
per_change_dBFS = to_per_dbfs - per_dBFS
bg_chang_dBFs = to_bg_dbfs - bg_dBFs
per_sound = per_sound.apply_gain(per_change_dBFS)
audio_sound = audio_sound.apply_gain(bg_chang_dBFs)
if offset>=0:
played_togther = per_sound.overlay(audio_sound,position=offset)
played_togther.export(out_path, format="mp3")
else:
played_togther = audio_sound.overlay(per_sound,position=-offset)
played_togther.export(out_path, format="mp3")
@AuthPermissionRequired()
def MixinPreview(request):
"""
混响预览
"""
if request.method == 'POST':
postdata = json.loads(request.body)
obj = verification.mixin_previews(postdata)
if obj.is_valid():
data = obj.clean()
user = get_user_info(request)
t = str(int(time.time())) + str(random.randint(0, 10000000000))
os.mkdir("./api/static/{}".format(t))
base_path = "./api/static/{}".format(t)
person_voice_path = base_path + "/voice-{}.mp3".format(str(random.randint(0, 10000000000)))
try:
# person_voice_file = requests.get(data.get('person_url'),verify=False).content
person_voice_file = get_oss_file(data.get('person_url'))
# bg_audio_file = requests.get(data.get('bg_url'),verify=False).content
bg_audio_file = get_oss_file(data.get('bg_url'))
except Exception as e:
return JsonResponse(ResponseFactory(code=201, message="上传物料链接获取不到资源,检查链接", data=None, status='fail'))
# #保存上传文件
with open(person_voice_path, "wb") as f:
f.write(person_voice_file)
f.close()
bg_audio_path = base_path + "/bg-{}.mp3".format(str(random.randint(0, 10000000000)))
# #保存上传文件
with open(bg_audio_path, "wb") as ff:
ff.write(bg_audio_file)
ff.close()
person_volume = data.get('person_volume')
bg_volume = data.get('bg_volume')
mixin_ratio = data.get('mix_type')
offset = data.get('offset')
# 查看时候需要切片段
begin_time = postdata.get('begin_time', '')
if begin_time != '':
# 获取人声音频时长
person_input_music = pydub.AudioSegment.from_file(person_voice_path)
duration = person_input_music.duration_seconds
# #伴奏音频切片
bg_input_music = pydub.AudioSegment.from_file(bg_audio_path)
# 截取音频 1000毫秒 = 1秒
bg_output_music = bg_input_music[begin_time * 1000:begin_time * 1000 + duration * 1000]
# 保存音频,指定音频比特率为64k
bg_output_music.export(bg_audio_path, bitrate="64k")
mixin_pre = models.MixinPreviews.objects.create(
activity_id=data['activity_id'],
user_id=user['id'],
url='',
created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")
)
t = threading.Thread(target=mixin,args=[person_voice_path,person_volume,bg_audio_path,bg_volume, mixin_ratio,offset,mixin_pre.id,base_path])
t.setDaemon(True)
t.start()
data = {'id':mixin_pre.id,'activity_id':mixin_pre.activity_id,'url':mixin_pre.url}
return JsonResponse(ResponseFactory(code=200, message="音频合成中", data=data, status='success'))
else:
return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail'))
else:
return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail'))
@AuthPermissionRequired()
def PartPreview(request):
"""
片段混响
"""
if request.method == 'POST':
obj = verification.part_mixin_previews(json.loads(request.body))
if obj.is_valid():
data = obj.clean()
user = get_user_info(request)
t = str(int(time.time())) + str(random.randint(0, 10000000000))
os.mkdir("./api/static/{}".format(t))
base_path = "./api/static/{}".format(t)
person_voice_path = base_path + "/voice-{}.mp3".format(str(random.randint(0, 10000000000)))
try:
# person_voice_file = requests.get(data.get('person_url')).content
person_voice_file = get_oss_file(data.get('person_url'))
# bg_audio_file = requests.get(data.get('bg_url')).content
bg_audio_file = get_oss_file(data.get('bg_url'))
except Exception as e:
return JsonResponse(ResponseFactory(code=201, message="上传物料链接获取不到资源,检查链接", data=None, status='fail'))
# #保存人声文件
with open(person_voice_path, "wb") as f:
f.write(person_voice_file)
f.close()
bg_audio_path = base_path + "/bg-{}.mp3".format(str(random.randint(0, 10000000000)))
# #保存伴奏文件
with open(bg_audio_path, "wb") as ff:
ff.write(bg_audio_file)
ff.close()
#提取伴奏片段
part_bg_path = base_path + "/part-bg-{}.mp3".format(str(random.randint(0, 10000000000)))
input_music = pydub.AudioSegment.from_mp3(bg_audio_path)
# 截取音频 1000毫秒 = 1秒
output_music = input_music[data.get('start_time')*1000:data.get('end_time')*1000]
# 保存音频,指定音频比特率为64k
output_music.export(part_bg_path, bitrate="64k")
person_volume = data.get('person_volume')
bg_volume = data.get('bg_volume')
mixin_ratio = data.get('mix_type')
offset = data.get('offset')
mixin_pre = models.MixinPreviews.objects.create(
activity_id=data['activity_id'],
user_id=user['id'],
url='',
created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")
)
t = threading.Thread(target=mixin,args=[person_voice_path,person_volume,part_bg_path,bg_volume, mixin_ratio,offset,mixin_pre.id,base_path])
t.setDaemon(True)
t.start()
data = {'id':mixin_pre.id,'activity_id':mixin_pre.activity_id,'url':mixin_pre.url}
return JsonResponse(ResponseFactory(code=200, message="音频合成中", data=data, status='success'))
else:
return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail'))
else:
return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail'))
@AuthPermissionRequired()
def MixinCheck(request):
if request.method == 'GET':
try:
id = int(request.GET['id'])
except Exception as e:
return JsonResponse(ResponseFactory(code=201, message="id参数错误", data=None, status='fail'))
mixin_pre = serializers.MixinPreviewsSerializer(models.MixinPreviews.objects.get(id=id,deleted_at=None),many=False)
return JsonResponse(ResponseFactory(code=200, message="获取成功", data=mixin_pre.data, status='success'))
else:
return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail'))
@AuthPermissionRequired()
def OnlineSave(request):
"""
在线上传
"""
if request.method == 'POST':
user = get_user_info(request)
try:
data = json.loads(request.body)
# 获取上次提交版本信息
obj = models.ActivityHasUsers.objects.filter(user_id=user['id'], activity_id=data['activity_id'],deleted_at=None).last()
if obj:
version = obj.version
if version:
version += 1
else:
version = 1
else:
version = 1
#预览完成保存
if data['demo_url'] != '':
#获取音频时长
try:
# demo_data = requests.get(data['demo_url'],verify=False).content
demo_data = get_oss_file(data['demo_url'])
except Exception as e:
return JsonResponse(ResponseFactory(code=201, message="音频地址获取不到资源,检查链接", data=None, status='fail'))
# #保存demo文件获取时长
demo_path = "./api/static/demo-{}.mp3".format(str(random.randint(0, 10000000000)))
with open(demo_path, "wb") as f:
f.write(demo_data)
f.close()
demo_music = pydub.AudioSegment.from_mp3(demo_path)
duration = demo_music.duration_seconds
# 删除零时文件
os.remove(demo_path)
ahu = models.ActivityHasUsers.objects.create(
activity_id=data['activity_id'],
user_id=user['id'],
demo_url=data['demo_url'],
durations = duration,
status=0,
syn_status=1,
syn_data=data,
type="Save",
version = version,
mode = 0,
sing_type=data.get('sing_type',None),
created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")
)
data = {'id':ahu.id,'activity_id':ahu.activity_id,'demo_url':ahu.demo_url}
return JsonResponse(ResponseFactory(code=200, message="保存成功", data=data, status='success'))
#未预览保存
else:
t = str(int(time.time())) + str(random.randint(0, 10000000000))
os.mkdir( os.getcwd() + "/api/static/{}".format(t))
base_path = os.getcwd() + "/api/static/{}".format(t)
person_voice_path = base_path + "/voice-{}.mp3".format(str(random.randint(0, 10000000000)))
try:
# person_voice_file = requests.get(data.get('person_url'),verify=False).content
person_voice_file = get_oss_file(data.get('person_url'))
# bg_audio_file = requests.get(data.get('bg_url'),verify=False).content
bg_audio_file = get_oss_file(data.get('bg_url'))
except Exception as e:
return JsonResponse(ResponseFactory(code=201, message="上传物料链接获取不到资源,检查链接", data=None, status='fail'))
# #保存上传文件
with open(person_voice_path, "wb") as f:
f.write(person_voice_file)
f.close()
bg_audio_path = base_path + "/bg-{}.mp3".format(str(random.randint(0, 10000000000)))
# #保存上传文件
with open(bg_audio_path, "wb") as ff:
ff.write(bg_audio_file)
ff.close()
person_volume = data.get('person_volume')
bg_volume = data.get('bg_volume')
mixin_ratio = data.get('mix_type')
offset = data.get('offset')
#查看时候需要切片段
begin_time = data.get('begin_time','')
if begin_time != '' :
# 获取人声音频时长
person_input_music = pydub.AudioSegment.from_mp3(person_voice_path)
duration = person_input_music.duration_seconds
# #伴奏音频切片
bg_input_music = pydub.AudioSegment.from_file(bg_audio_path)
# 截取音频 1000毫秒 = 1秒
bg_output_music = bg_input_music[begin_time*1000:begin_time*1000+duration*1000]
# 保存音频,指定音频比特率为64k
bg_output_music.export(bg_audio_path, bitrate="64k")
ahu = models.ActivityHasUsers.objects.create(
activity_id=data['activity_id'],
user_id=user['id'],
demo_url='',
syn_status = 0,
syn_data = data ,
status=0,
type="Save",
mode=0,
version = version,
sing_type=data.get('sing_type', None),
created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")
)
t = threading.Thread(target=mixin_save,
args=[person_voice_path, person_volume, bg_audio_path, bg_volume, mixin_ratio, offset,
ahu.id, base_path])
t.setDaemon(True)
t.start()
data = {'id': ahu.id, 'activity_id': ahu.activity_id, 'demo_url': ahu.demo_url}
return JsonResponse(ResponseFactory(code=200, message="音频合成中,合成后会自动保存", data=data, status='success'))
except Exception as e:
logger.info('提交异常:用户ID:{},参数:{},错误信息:{}'.format(user['id'], request.body,e))
else:
return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail'))
@AuthPermissionRequired()
def JoinActivity(request):
if request.method != 'POST':
return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail'))
user = get_user_info(request)
# 检查是否有提交权限
permission = user_permission(user['id'])
if 2 not in permission:
return JsonResponse(ResponseFactory(code=400, message='用户无此权限', data=None, status='fail'))
post_data = json.loads(request.body)
dataobj = verification.join_activity(post_data)
if not dataobj.is_valid():
return JsonResponse(ResponseFactory(code=400, message=verification.error_message(dataobj), data=None, status='fail'))
dataobj = dataobj.clean()
activity_id = dataobj.get('activity_id')
url = dataobj.get('url')
type = dataobj.get('join_type')
sing_type = dataobj.get('sing_type')
is_hide = post_data.get('is_hide',1)
# 判断活动状态
activity_status = models.Activitys.objects.filter(id=activity_id).first().status
if activity_status != 1:
return JsonResponse(ResponseFactory(code=201, message="活动已结束", data=None, status='fail'))
self_price = post_data.get('self_price',None)
#校验自主报价参数
if self_price:
ver = verification.SubmitPriceVerification(data=self_price)
if not ver.is_valid():
return JsonResponse(
ResponseFactory(code=400, message=verification.error_message(ver), data=None, status='fail'))
if self_price['value']['amounts']:
if not (0 <= self_price['value']['amounts'] <= 9999999): return JsonResponse(
ResponseFactory(code=201, message="金额在0-9999999之间", data=None, status='fail'))
if self_price['value']['ratio']:
if not (0 <= self_price['value']['ratio'] <= 100): return JsonResponse(
ResponseFactory(code=201, message="分成比列在0%-100%之间", data=None, status='fail'))
try:
# 获取上次提交版本信息
ahu_obj = models.ActivityHasUsers.objects.filter(user_id=user['id'], activity_id=activity_id,deleted_at=None).last()
if ahu_obj:
version = ahu_obj.version
if version:version += 1
else:version = 1
else:
version = 1
try:
demo_data = get_oss_file(url)
except Exception as e:
return JsonResponse(ResponseFactory(code=201, message="音频地址获取不到资源,检查链接", data=None, status='fail'))
# #保存demo文件获取时长
file_type = url.split('.')[-1]
demo_path = "./api/static/demo-{}.{}".format(str(random.randint(0, 10000000000)), file_type)
with open(demo_path, "wb") as f:
f.write(demo_data)
f.close()
demo_music = pydub.AudioSegment.from_file(demo_path)
duration = demo_music.duration_seconds
# 删除零时文件
os.remove(demo_path)
if type == 'Submit':
try:
with transaction.atomic():
models.ActivityHasUsers.objects.filter(user_id=user['id'], activity_id=activity_id).update(type="Save", updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"))
ahu = models.ActivityHasUsers.objects.create(
activity_id=activity_id,
user_id=user['id'],
demo_url=url,
durations=duration,
status=0,
type=type,
open_id='',
syn_status=1,
mode=0,
is_hide = is_hide,
version=version,
sing_type=sing_type,
submit_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")
)
#存入自主报价
if self_price:
models.ActivityUserHasPrices.objects.update_or_create(
user_id=user['id'], activity_id=activity_id,
defaults={
"value": self_price['value'],
"is_deduct": self_price['is_deduct'],
"is_talk": self_price['is_talk'],
"address_id": self_price['address_id'],
"is_accept_address": self_price['is_accept_address'],
"created_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
"updated_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S"), },
)
# 更新到动态
is_tidings = post_data.get("is_tidings", 0)
if is_tidings == 1:
models.UserHasTidings.objects.create(user_id=user['id'], activity_id=activity_id,type=2, url=url,created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"))
# 提交作品计数 1.先检查用户对该作品之前是否有提交且未读的消息
user_msg = models.UserMessages.objects.filter(is_read=0, sender_id=user['id'],activity_id=activity_id, deleted_at=None, type=3)
if user_msg:
user_msg.update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"))
# 获取全体管理员和推荐人open_id
project_id = models.Activitys.objects.filter(id=activity_id).first().project_id
project = models.Projects.objects.filter(id=project_id).first()
project_user_ids = []
if project:
if project.is_public:project_user_ids = list(models.UserHasProjects.objects.filter(project_id=project_id).values_list('user_id',flat=True))
else:project_user_ids = [models.Activitys.objects.filter(id=activity_id).first().user_id]
project_user_unionid = list(
models.Users.objects.filter(id__in=project_user_ids, deleted_at=None, status=1).values_list(
'unionid', flat=True))
admin_unionid = list(models.Users.objects.filter(scope=1,deleted_at=None,status=1).values_list('unionid', flat=True))
push_open_ids = list(
models.WechatOfficialUsers.objects.filter(union_id__in=admin_unionid + project_user_unionid,is_subscribe=1).values_list('open_id', flat=True))
song_name = models.Activitys.objects.filter(id=activity_id).first().song_name
# 再创建消息
business_id = user['business_id']
if business_id:
# 获取推荐人公众号open_id
unionid = models.Users.objects.filter(id=business_id).values_list('unionid', flat=True)
wechat_official = models.WechatOfficialUsers.objects.filter(union_id__in=unionid,is_subscribe=1).last()
if wechat_official:
# 公众号推送
p_data = {'channel': 'singer_related', 'open_id': [wechat_official.open_id],
'data': {"title": "您的歌手参加了试唱歌曲",
"name": user['nick_name'] + "("+user['real_name']+")",
"intro": "参加了试唱歌曲《{}》".format(song_name),
"remark": "点击前往 >",
"page": "/packageMy/pages/like?tab=2"}}
pushSubscribeMessage(p_data)
# 发给绑定的推荐人
m_data = {'sender_id': user['id'], 'receivers': [business_id],
'activity_id': activity_id, 'type': 3, 'is_bind': 1}
createMessage(m_data)
# 极光推送-提交作品推荐人
j_title = "您的歌手参加了试唱"
j_content = "您的歌手{}参加了试唱活动《{}》".format(user['nick_name'], song_name)
jdata = {"title": j_title, "content": j_content, "content_type": "text",
"receiver_value": [business_id],
"extras": {"type": "ToTaSing", "value": ""}}
JPush().jpush_v3(jdata)
# 给全体管理员和项目管理员推服务号消息
p_data = {'channel': 'activity_join', 'open_id': push_open_ids,
'data': {
"first": "{}({})提交了试唱作品".format(user['nick_name'], user['real_name']),
"keyword1": "《"+song_name+"》",
"keyword2": timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
"remark": "点击试听 >", "page": "/pages/index/index"}
}
pushSubscribeMessage(p_data)
# 外部管理员id
activity_manage_ids = list(
models.UserManageActivitie.objects.filter(activity_id=activity_id).values_list(
'user_id', flat=True))
# 发送系统消息(平台管理员+项目管理员+外部管理员)
receivers = list(models.Users.objects.filter(scope=1).values_list('id', flat=True))
receivers = list(set(receivers + project_user_ids +activity_manage_ids))
m_data = {'sender_id': user['id'], 'receivers': receivers,
'activity_id': activity_id,
'type': 3, 'is_bind': 0}
createMessage(m_data)
# 极光推送-提交作品全体管理员
j_title = "有新用户提交试唱"
j_content = "{}参与了试唱《{}》".format(user['nick_name'], song_name)
jdata = {"title": j_title, "content": j_content, "content_type": "text",
"receiver_value": receivers,
"extras": {"type": "ToPlatfromSing", "value": ""}}
JPush().jpush_v3(jdata)
except Exception as e:
return JsonResponse(ResponseFactory(code=201, message="提交失败:{}".format(e), data=None, status='fail'))
if sing_type == 'Part':
# 歌手积分
user_point_record(user_id=user['id'], type='SubmitPart', activity_id=activity_id)
# 推荐人积分
if user['business_id']:
user_point_record(user_id=user['business_id'], type='SingerSubmitPart',activity_id=activity_id,singer_id=user['id'])
else:
# 歌手积分
user_point_record(user_id=user['id'], type='SubmitFull', activity_id=activity_id,)
# 推荐人积分
if user['business_id']:
user_point_record(user_id=user['business_id'], type='SingerSubmitFull',activity_id=activity_id,singer_id=user['id'])
data = {'id': ahu.id, 'activity_id': ahu.activity_id, 'demo_url': ahu.demo_url}
return JsonResponse(ResponseFactory(code=200, message="提交成功", data=data, status='success'))
else:
ahu = models.ActivityHasUsers.objects.create(
activity_id=activity_id,
user_id=user['id'],
demo_url=url,
durations=duration,
status=0,
type=type,
open_id='',
mode=0,
syn_status = 1,
version=version,
sing_type=sing_type,
created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")
)
data = {'id': ahu.id, 'activity_id': ahu.activity_id, 'demo_url': ahu.demo_url}
return JsonResponse(ResponseFactory(code=200, message="保存成功", data=data, status='success'))
except Exception as e:
logger.info('提交异常:用户ID:{},参数:{},错误信息:{}'.format(user['id'], request.body, e))
return JsonResponse(ResponseFactory(code=201, message="服务器网络波动,请稍后重试", data=None, status='fail'))
@AuthPermissionRequired()
def AuditionMaterials(request):
if request.method == 'GET':
activity_id = request.GET['activity_id']
user_id = get_user_info(request)['id']
queryset = models.Activitys.objects.filter(id=activity_id).first()
activity_ser = serializers.ActivityDetailSerializer(queryset,many=False,context={"user_id":user_id,"project_many":False},
fields=['id','song_name','lyric','clip_lyric','cover','status','project_id','sex','mark','speed','lang','guide_duration','guide_clip_duration','is_collection','is_confirm_share','project','tags','is_promote','estimate_release_at','publish_at','comfirm_time','total_song_count','online_song_count','public_audio_count','arranger'])
activity = activity_ser.data
#活动配置信息
config_ids = list(models.SystemConfig.objects.filter(identifier__in=['activity_lang', 'activity_speed', 'activity_sex','activity_mark']).values_list('id',flat=True).all())
configs = models.SystemConfig.objects.filter(parent_id__in=config_ids).values_list('identifier','name','content')
lang = activity['lang'] if activity['lang'] else []
langs = []
for config in configs:
if config[0] == activity['sex']:
activity['sex'] = config[1] if activity['sex'] else None
if config[0] == activity['mark']:
activity['mark'] = config[2] if activity['mark'] else None
if config[0] == activity['speed']:
activity['speed'] = config[1] if activity['speed'] else None
if config[0] in lang:
langs.append(config[1])
activity['lang'] = langs
ser = serializers.ActivityMaterialsSerializer(models.ActivityMaterials.objects.filter(activity_id=activity_id,deleted_at=None),many=True)
data = {'activity':activity,'materials':ser.data}
# 积分
user_point_record(user_id=user_id, type='Listen',activity_id=activity_id)
return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success'))
else:
return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail'))
@AuthPermissionRequired()
def ActivityMaterials(request):
if request.method == 'GET':
activity_id = request.GET['activity_id']
user_id = get_user_info(request)['id']
queryset = models.Activitys.objects.filter(id=activity_id).first()
activity_ser = serializers.ActivityDetailSerializer(queryset, many=False, context={"user_id": user_id,"project_many":False},
fields=['id','song_name','lyric','sex','mark','speed','lang','guide','guide_duration','guide_clip','guide_clip_duration','karaoke','karaoke_clip','clip_lyric','cover','status','project_id','is_collection','is_confirm_share','project','tags','is_promote','estimate_release_at','publish_at','guide_duration','guide_clip_duration','comfirm_time','total_song_count','online_song_count','public_audio_count','arranger'])
activity = activity_ser.data
# 活动配置信息
config_ids = list(models.SystemConfig.objects.filter(
identifier__in=['activity_lang', 'activity_speed', 'activity_sex', 'activity_mark']).values_list('id',
flat=True).all())
configs = models.SystemConfig.objects.filter(parent_id__in=config_ids).values_list('identifier', 'name',
'content')
lang = activity['lang'] if activity['lang'] else []
langs = []
for config in configs:
if config[0] == activity['sex']:
activity['sex'] = config[1] if activity['sex'] else None
if config[0] == activity['mark']:
activity['mark'] = config[2] if activity['mark'] else None
if config[0] == activity['speed']:
activity['speed'] = config[1] if activity['speed'] else None
if config[0] in lang:
langs.append(config[1])
activity['lang'] = langs
data = {'activity':activity}
# 积分
user_point_record(user_id=user_id, type='Listen',activity_id=activity_id)
return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success'))
else:
return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail'))
def SendEmail(request,user):
activity_id = request.GET['activity_id']
activity = models.Activitys.objects.filter(id=activity_id).first()
subject = '【海星试唱】-' + activity.song_name + '-试唱物料资源'
message = '{},您好:\n' \
'\n 【海星试唱】-{}-物料资源如下,包含导唱(含人声)、伴奏(不含人声)、歌词内容。请复制下方链接内容在浏览器打开进行下载。\n' \
'\n导唱(含人声):{}' \
'\n' \
'\n伴奏(不含人声):{}' \
'\n' \
'\n《歌词》:\n' \
'{}' \
'\n' \
'\n 1.本邮件含有保密信息,仅限于收件人所用。禁止任何人未经发件人许可以任何形式(包括但不限于部分地泄露、复制或散发)不当地使用本邮件中的信息。如果您错收了本邮件,请您立即电话或邮件通知发件人并删除本邮件。' \
'\n 2.本公司员工存在受贿、索贿、贪污、盗窃、挪用资金等行为,请将相关证据以邮件形式发送至公司反腐败举报邮箱:service@hikoon.com' \
'\n' \
'\n' \
'对于您通过本邮件所获取的试唱资料(包括但不限于歌词、伴奏、音频等)及/或您录制的试唱音视频,您仅能用于个人试唱录制使用,并仅能上传至海星试唱平台,未经海星试唱平台书面同意,您不得泄露给任何第三方或发布在任何其他平台,试唱资料及您使用试唱资料制作的全部音乐作品/录音录像制品/视听作品的完整著作权和邻接权均归属于北京海葵科技有限公司(以下简称“海葵”)或其指定的第三方,您不得抄袭、模仿或提前泄露在短视频或音乐平台,也不可在未取得海葵书面许可的情况下翻唱、二次创作。如因您未按规定使用试唱资料及/或您录制的试唱音视频,海葵或其指定的第三方有权要求您赔偿因此造成的一切直接损失、间接损失(包括但不限于词曲成本、软件运营成本、海葵支付的差旅费、律师费、公证费、诉讼/仲裁费、保全费、鉴定费等)。' \
.format(user['nick_name'], activity.song_name, activity.expand['guide_source']['url'],activity.expand['karaoke_source']['url'],
activity.lyric)
send_mail(
subject=subject,
message=message,
from_email=settings.EMAIL_HOST_USER,
recipient_list=[user['email'], settings.EMAIL_HOST_USER] # 接收者的邮箱账号
)
@AuthPermissionRequired()
def SendMaterials(request):
if request.method != 'GET':
return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail'))
user = get_user_info(request)
if not user['email']:
return JsonResponse(ResponseFactory(code=201, message="请先绑定邮箱", data=None, status='success'))
t = threading.Thread(target=SendEmail,
args=[request,user])
t.setDaemon(True)
t.start()
return JsonResponse(ResponseFactory(code=200, message="发送中,请稍等片刻...", data=None, status='success'))
def SplitAudio(request):
"""
音频文件拆分
"""
post_data = json.loads(request.body)
obj = verification.SplitAudio(data=post_data)
loggin.logger.info('拆分参数:{}'.format(post_data))
if not obj.is_valid():
return JsonResponse({"code":"400", "message":verification.error_message(obj), "data":None, "status":"fail"})
id = obj.data['activity_id']
status = obj.data['status']
data = str({"id":id,"status":status,"time":timezone.now().strftime("%Y-%m-%d %H:%M:%S")})
con.lpush('split_audio_queue',data)
return JsonResponse({"code":"200", "message":"已添加到拆分队列中", "data":None, "status":":success"})
@AuthPermissionRequired()
def AotoSubmit(request):
"""
自主提交
"""
if request.method == "POST":
user = get_user_info(request)
#检查是否有提交权限
permission = user_permission(user['id'])
if 2 not in permission:
return JsonResponse(ResponseFactory(code=400, message='用户无此权限', data=None, status='fail'))
post_data = json.loads(request.body)
obj = verification.aoto_submit(post_data)
is_hide = post_data.get('is_hide', 1)
if obj.is_valid():
data = obj.clean()
type = data['type']
# 校验自主报价参数
self_price = post_data.get('self_price', None)
if self_price:
ver = verification.SubmitPriceVerification(data=self_price)
if not ver.is_valid():
return JsonResponse(
ResponseFactory(code=400, message=verification.error_message(ver), data=None, status='fail'))
if self_price['value']['amounts']:
if not (0 <= self_price['value']['amounts'] <= 9999999): return JsonResponse(
ResponseFactory(code=201, message="金额在0-9999999之间", data=None, status='fail'))
if self_price['value']['ratio']:
if not (0 <= self_price['value']['ratio'] <= 100): return JsonResponse(
ResponseFactory(code=201, message="分成比列在0%-100%之间", data=None, status='fail'))
#判断活动状态
activity_status = models.Activitys.objects.filter(id = data['activity_id']).first().status
if activity_status != 1:
return JsonResponse(ResponseFactory(code=201, message="活动已结束", data=None, status='fail'))
#获取小程序openid
try:
vx_code = post_data.get("vx_code","")
open_id, unionid = WeChatApi(vx_code)
except:
open_id = ''
# 获取上次提交版本信息
obj = models.ActivityHasUsers.objects.filter(user_id=user['id'], activity_id=data['activity_id'],deleted_at=None).last()
if obj:
version = obj.version
if version:
version += 1
else:
version = 1
else:
version = 1
try:
demo_data = get_oss_file(data['url'])
except Exception as e:
return JsonResponse(ResponseFactory(code=201, message="音频地址获取不到资源,检查链接", data=None, status='fail'))
# #保存demo文件获取时长
demo_path = "./api/static/demo-{}.mp3".format(str(random.randint(0, 10000000000)))
with open(demo_path, "wb") as f:
f.write(demo_data)
f.close()
duration = librosa.get_duration(filename=demo_path)
# 删除零时文件
os.remove(demo_path)
try:
with transaction.atomic():
if type == 'Submit':
models.ActivityHasUsers.objects.filter(user_id=user['id'],activity_id=data['activity_id']).update(type="Save",updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"))
ahu = models.ActivityHasUsers.objects.create(
activity_id = data['activity_id'],
user_id = user['id'],
demo_url = data['url'],
durations=duration,
wav_url = post_data.get("wav_url",""),
wav_durations=post_data.get("wav_durations", 0),
status = 0,
syn_status = 1,
type = type,
open_id = open_id,
is_hide = is_hide,
mode = 1,
version = version,
submit_at= timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
created_at = timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")
)
# 存入自主报价
if self_price:
models.ActivityUserHasPrices.objects.update_or_create(
user_id=user['id'],activity_id=data['activity_id'],
defaults={
"value": self_price['value'],
"is_deduct": self_price['is_deduct'],
"is_talk": self_price['is_talk'],
"address_id": self_price['address_id'],
"is_accept_address": self_price['is_accept_address'],
"created_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
"updated_at": timezone.now().strftime("%Y-%m-%d %H:%M:%S"), },
)
#更新到动态
is_tidings = post_data.get("is_tidings", 0)
if is_tidings == 1:
models.UserHasTidings.objects.create(user_id=user['id'],activity_id=data['activity_id'],type=2,url=data['url'], created_at = timezone.now().strftime("%Y-%m-%d %H:%M:%S"),updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"))
# 提交作品计数 1.先检查用户对该作品之前是否有提交且未读的消息
user_msg = models.UserMessages.objects.filter(is_read=0, sender_id=user['id'],activity_id=data['activity_id'], deleted_at=None, type=3)
if user_msg:
user_msg.update(deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"))
# 获取全体管理员和推荐人和项目管理员open_id
project_id = models.Activitys.objects.filter(id=data['activity_id']).first().project_id
project = models.Projects.objects.filter(id=project_id).first()
project_user_ids = []
if project:
if project.is_public:project_user_ids = list(models.UserHasProjects.objects.filter(project_id=project_id).values_list('user_id',flat=True))
else:project_user_ids = [models.Activitys.objects.filter(id=data['activity_id']).first().user_id]
project_user_unionid = list(models.Users.objects.filter(id__in=project_user_ids,deleted_at=None,status=1).values_list('unionid', flat=True))
admin_unionid = list(models.Users.objects.filter(scope=1,deleted_at=None,status=1).values_list('unionid', flat=True))
push_open_ids = list(models.WechatOfficialUsers.objects.filter(union_id__in=admin_unionid+project_user_unionid,is_subscribe=1).values_list('open_id', flat=True))
song_name = models.Activitys.objects.filter(id=data['activity_id']).first().song_name
# 再创建消息
business_id = user['business_id']
if business_id:
#获取推荐人公众号open_id
unionid = models.Users.objects.filter(id=business_id).values_list('unionid', flat=True)
wechat_official = models.WechatOfficialUsers.objects.filter(union_id__in=unionid,is_subscribe=1).last()
if wechat_official:
# 公众号推送
p_data = {'channel': 'singer_related', 'open_id': [wechat_official.open_id],
'data': {"title": "您的歌手参加了试唱歌曲", "name": user['nick_name']+"("+user['real_name']+")",
"intro": "参加了试唱歌曲《{}》".format(song_name),
"remark": "点击前往 >",
"page": "/packageMy/pages/like?tab=2"}}
pushSubscribeMessage(p_data)
#发给绑定的推荐人
m_data = {'sender_id': user['id'], 'receivers': [business_id], 'activity_id': data['activity_id'],'type': 3,'is_bind':1}
createMessage(m_data)
# 极光推送-提交作品推荐人
j_title = "您的歌手参加了试唱"
j_content = "您的歌手{}参加了试唱活动《{}》".format(user['nick_name'], song_name)
jdata = {"title": j_title, "content": j_content, "content_type": "text",
"receiver_value": [business_id],
"extras": {"type": "ToTaSing", "value": ""}}
JPush().jpush_v3(jdata)
#给全体管理员和项目管理员推服务号消息
p_data = {'channel': 'activity_join', 'open_id': push_open_ids,
'data': {"first":"{}({})提交了试唱作品".format(user['nick_name'],user['real_name']),"keyword1": "《"+song_name+"》", "keyword2": timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
"remark": "点击试听 >","page":"/pages/index/index"}
}
pushSubscribeMessage(p_data)
#外部管理员id
activity_manage_ids = list(models.UserManageActivitie.objects.filter(activity_id=data['activity_id']).values_list('user_id',flat=True))
# 发送系统消息(平台管理员+项目管理员+外部管理员)
receivers = list(models.Users.objects.filter(scope=1).values_list('id', flat=True))
receivers = list(set(receivers+project_user_ids+activity_manage_ids))
m_data = {'sender_id': user['id'], 'receivers': receivers,'activity_id': data['activity_id'], 'type': 3,'is_bind':0}
createMessage(m_data)
# 极光推送-提交作品全体管理员
j_title = "有新用户提交试唱"
j_content = "{}参与了试唱《{}》".format(user['nick_name'],song_name)
jdata = {"title": j_title, "content": j_content, "content_type": "text",
"receiver_value": receivers,
"extras": {"type": "ToPlatfromSing", "value": ""}}
JPush().jpush_v3(jdata)
# 歌手积分
user_point_record(user_id=user['id'], type='AutoSubmit', activity_id=data['activity_id'])
# 推荐人积分
if user['business_id']:
user_point_record(user_id=user['business_id'], type='SingerAutoSubmit',
activity_id=data['activity_id'], singer_id=user['id'])
data = {'id': ahu.id, 'activity_id': ahu.activity_id, 'demo_url': ahu.demo_url}
return JsonResponse(ResponseFactory(code=200, message="提交成功", data=data, status='success'))
else:
ahu = models.ActivityHasUsers.objects.create(
activity_id=data['activity_id'],
user_id=user['id'],
demo_url=data['url'],
durations=duration,
wav_url=post_data.get("wav_url", ""),
wav_durations=post_data.get("wav_durations", 0),
status=0,
syn_status=1,
type=type,
open_id=open_id,
is_hide=is_hide,
mode=1,
version=version,
submit_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")
)
data = {'id': ahu.id, 'activity_id': ahu.activity_id, 'demo_url': ahu.demo_url}
return JsonResponse(ResponseFactory(code=200, message="保存成功", data=data, status='success'))
except Exception as e:
logger.info('提交异常:用户ID:{},参数:{},错误信息:{}'.format(user['id'], request.body, e))
return JsonResponse(ResponseFactory(code=201, message="提交失败:{}".format(e), data=None, status='fail'))
else:
return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail'))
else:
return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail'))
def toFileData(file_name,file_type):
path = './api/static/'
t = str(int(time.time())) + str(random.randint(0, 10000000000))
file_path = path + t + "." + file_type
os.system("ffmpeg -i "+ path+file_name+ " " + file_path)
with open(file_path, 'rb') as f:
fileData = f.read()
f.close()
#删除零时文件
os.remove(file_path)
return fileData
# @AuthPermissionRequired()
def UploadAudio(request):
if request.method == "POST":
fileData = request.FILES.get('file')
if not fileData:
return JsonResponse(ResponseFactory(code=400, message="未读取到上传文件", data=None, status='fail'))
file_type = fileData.name.split('.')[1]
if file_type == 'mp3':
file_url = auto_upload_audio(fileData.read(),'mp3')
else:
path = './api/static/'
t = str(int(time.time())) + str(random.randint(0, 10000000000))
filename = t + "." + file_type
with open(path + filename, "wb") as f:
f.write(fileData.read())
f.close()
fileData = toFileData(filename,'mp3')
file_url = auto_upload_audio(fileData,'mp3')
os.remove(path + filename)
data = {"type": "mp3", "name": "", "url": file_url, "size": "", "disk": "oss", "created_at": "", "id": 0}
return JsonResponse(ResponseFactory(code=200, message="上传成功", data=data, status='success'))
else:
return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail'))
class Collection(APIView):
@method_decorator(AuthPermissionRequired())
def get(self,request):
status = request.GET.get('status','all') #默认所有
text = request.GET.get('text') #默认所有
user_id = get_user_info(request)['id']
ids = list(models.UserActivityCollections.objects.filter(user_id=user_id,deleted_at=None).order_by('-created_at').values_list('activity_id',flat=True))
idList = ",".join('%s' % id for id in ids)
kwargs = {"deleted_at":None,"id__in":ids}
if status == 'active':kwargs['status'] = 1
if text:kwargs['song_name__icontains'] = text
queryset = models.Activitys.objects.filter(**kwargs).extra(select={'m': 'FIELD(id,{})'.format(idList)}, order_by=['m'])
page_obj = PageNumberPagination()
page_data = page_obj.paginate_queryset(queryset, request)
activitys = serializers.CollectionActivitysSerializer(page_data, many=True, context={"user_id": user_id}).data
# 活动配置信息
config_ids = list(models.SystemConfig.objects.filter(
identifier__in=['activity_lang', 'activity_speed', 'activity_sex', 'activity_mark']).values_list('id',
flat=True).all())
configs = models.SystemConfig.objects.filter(parent_id__in=config_ids).values_list('identifier', 'name',
'content')
for activity in activitys:
lang = activity['lang'] if activity['lang'] else []
langs = []
for config in configs:
if config[0] == activity['sex']:
activity['sex'] = config[1] if activity['sex'] else None
if config[0] == activity['mark']:
activity['mark'] = config[2] if activity['mark'] else None
if config[0] == activity['speed']:
activity['speed'] = config[1] if activity['speed'] else None
if config[0] in lang:
langs.append(config[1])
activity['lang'] = langs
data = {"activitys": activitys, "count": len(queryset)}
return JsonResponse(ResponseFactory(code=200, message="获取成功", data=data, status='success'))
@method_decorator(AuthPermissionRequired())
def post(self,request):
obj = verification.collection(json.loads(request.body))
if obj.is_valid():
data = json.loads(request.body)
user = get_user_info(request)
is_active = models.UserActivityCollections.objects.filter(user_id=user['id'],activity_id=data['activity_id'], deleted_at=None)
if is_active:
return JsonResponse(ResponseFactory(code=400, message='请勿重复收藏', data=None, status='fail'))
try:
with transaction.atomic():
models.UserActivityCollections.objects.create(
user_id=user['id'],
activity_id=data['activity_id'],
created_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),
updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S")
)
# 消息计数
business_id = user['business_id']
role = user['role']
#有商务且为歌手
if business_id and role=='Singer':
m_data = {'receivers': [business_id], 'sender_id': user['id'],'activity_id':data['activity_id'], 'type': 2,'is_bind':1}
createMessage(m_data)
# 推送消息给推荐人
business_unionid = models.Users.objects.filter(id=business_id).first().unionid
business_wechat_official = models.WechatOfficialUsers.objects.filter(union_id=business_unionid,is_subscribe=1).last()
song_name = models.Activitys.objects.filter(id=data['activity_id']).first().song_name
if business_wechat_official:
business_open_id = business_wechat_official.open_id
name = user['nick_name'] + "({})".format(user['real_name'])
p_data = {'channel': 'singer_related', 'open_id': [business_open_id],
'data': {"title": "您的歌手收藏了试唱活动", "name": name, "intro": "收藏了试唱活动《{}》".format(song_name),
"remark": "点击前往 >",
"page": "packageMy/pages/like?tab=1"}}
pushSubscribeMessage(p_data)
# 极光推送-歌手收藏
j_title = "您的歌手收藏了试唱"
j_content = "您的歌手{}收藏了试唱活动《{}》".format( user['nick_name'],song_name)
jdata = {"title": j_title, "content": j_content, "content_type": "text",
"receiver_value": [business_id],
"extras": {"type": "ToTaCollection", "value": ""}}
JPush().jpush_v3(jdata)
except Exception as e:
return JsonResponse(ResponseFactory(code=201, message="收藏失败。请联系管理员", data=None, status='fail'))
return JsonResponse(ResponseFactory(code=200, message="收藏成功", data=None, status='success'))
else:
return JsonResponse(
ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail'))
@method_decorator(AuthPermissionRequired())
def delete(self,request):
obj = verification.collection(json.loads(request.body))
if obj.is_valid():
data = json.loads(request.body)
user = get_user_info(request)
is_active = models.UserActivityCollections.objects.filter( user_id=user['id'],activity_id=data['activity_id'],deleted_at=None)
if is_active:
try:
with transaction.atomic():
is_active.update(updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),deleted_at = timezone.now().strftime("%Y-%m-%d %H:%M:%S") )
#取消收藏取消计数
m_data = {"sender_id":user['id'],"activity_id":data['activity_id'],"type":2}
deleteMessage(m_data)
except Exception as e:
return JsonResponse(ResponseFactory(code=201, message="取消失败。请联系管理员", data=None, status='fail'))
return JsonResponse(ResponseFactory(code=200, message="已取消收藏", data=None, status='success'))
else:
return JsonResponse(ResponseFactory(code=400, message='未收藏不能取消', data=None, status='fail'))
else:
return JsonResponse(
ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail'))
def cancelcollection(request):
if request.method == "POST":
obj = verification.collection(json.loads(request.body))
if obj.is_valid():
data = json.loads(request.body)
user = get_user_info(request)
is_active = models.UserActivityCollections.objects.filter(user_id=user['id'],activity_id=data['activity_id'], deleted_at=None)
if is_active:
try:
with transaction.atomic():
is_active.update(updated_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"),deleted_at=timezone.now().strftime("%Y-%m-%d %H:%M:%S"))
# 取消收藏取消计数
m_data = {"sender_id": user['id'], "activity_id": data['activity_id'], "type": 2}
deleteMessage(m_data)
except:
return JsonResponse(ResponseFactory(code=201, message="取消失败。请联系管理员", data=None, status='fail'))
return JsonResponse(ResponseFactory(code=200, message="已取消收藏", data=None, status='success'))
else:
return JsonResponse(ResponseFactory(code=400, message='未收藏不能取消', data=None, status='fail'))
else:
return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail'))
else:
return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail'))
class ShareUsersList(APIView):
@method_decorator(AuthPermissionRequired())
def get(self,request):
text = request.GET.get('text','')
if text:
user_id = get_user_info(request)['id']
queryset = models.Users.objects.filter(Q(nick_name__icontains=text) | Q(real_name__icontains=text),~Q(id=user_id),audit_status=1,status=1,deleted_at=None)
else:
return JsonResponse(ResponseFactory(code=200, message="获取成功", data=[], status='success'))
users = serializers.BusinessSerializer(queryset,many=True).data
return JsonResponse(ResponseFactory(code=200, message="获取成功", data=users, status='success'))
class ShareUsers(APIView):
@method_decorator(AuthPermissionRequired())
def post(self,request):
try:
post_data = json.loads(request.body)
except:
return JsonResponse(ResponseFactory(code=400, message="参数错误", data=None, status='fail'))
obj = verification.ShareUsersVerify(data=post_data)
if not obj.is_valid():
return JsonResponse(ResponseFactory(code=400, message=verification.error_message(obj), data=None, status='fail'))
user_id = get_user_info(request)['id']
activity_id = obj.data.get('activity_id')
share_id = obj.data.get('share_id')
models.ActivityShareUsers.objects.update_or_create(
activity_id=activity_id, user_id=user_id,
defaults={'share_id': share_id,'created_at':timezone.now().strftime("%Y-%m-%d %H:%M:%S"),'updated_at':timezone.now().strftime("%Y-%m-%d %H:%M:%S")},
)
return JsonResponse(ResponseFactory(code=200, message="保存成功", data=None, status='success'))
def test(request):
if request.method == "POST":
fileData = json.loads(request.body).get('file')
print (type(fileData),fileData)
import numpy as np
data = np.array(fileData.get('data'))
data.tofile('./ttt.mp3')
return JsonResponse(ResponseFactory(code=200, message="上传成功", data=fileData, status='success'))
else:
return JsonResponse(ResponseFactory(code=400, message="不支持的请求方法", data=None, status='fail'))