Hôm nay, mình sẽ hướng dẫn các bạn cách viết code hệ thống ranking member cho group cả thuật toán lẫn viết code. Ở post này, mình sẽ viết bằng ngôn ngữ Autoit, còn thím nào muốn chuyển qua php hay gì đó thì chỉ cần thay đổi vài chỗ và hàm tương ứng là xong rồi :V
I. Ý tưởng Thật ra, ý tưởng này mình thấy đã lâu, cụ thể là mấy tháng trước anh Huỳnh Phúc Huy bên group "Lập trình Autoit" đã ra mắt chức năng này, hay mới gần đây là anh Mạnh Tuấn (với điều này đã lôi kéo được khá nhiều lượt tương tác cho group "J2TeaM Community") . Mình thấy khá hay, nên muốn bắt tay vào làm thử.
II. Chuẩn bịUDF
+ Json (tác giả : Ward và Zserge)
Token
+ Các bạn có thể lấy token của HTC Sense (Cái này thưởng thấy ở trong mấy hệ thống auto like, yên tâm, sẽ không sao, nếu bạn không sài mấy hệ thống đó, token của bạn sẽ vẫn được an toàn) - tham khảo tại đây
+ Hoặc bạn có thể tự tạo app - đây là phương pháp an toàn - tham khảo tại đây
Và một số kiến thức về lập trình (trong bài, mình có sử dụng đệ quy, để dễ tích hợp hơn với hệ thống ranking này) - bạn có thể tham khảo trên mạng
III. Cơ chế Tạm giống của anh Mạnh Tuấn
+ Người Post bài : +3 điểm . + 1 điểm đối với 1 lượt like bài. +1 điểm cho 1 lượt cmt. +1 điểm cho 1 lượt share
+ Người không đăng bài : +1 điểm có reactions bài, +1 điểm cho 1 lượt cmt,...
IV. Thuật toán Thuật toán của mình thì chắc chả có gì đăt biệt, nhưng đây chỉ là ý tưởng riêng của mình (có thể sẽ chậm hơn nhìu so với mấy bậc tiền bối kia :3 )
Mình nghĩ là: thực hiện lọc trùng id trong lúc chạy hơn là lọc trùng sau khi có id (nhưng chắc sẽ chậm hơn cách của anh Mạnh Tuấn :3 )
+ Đầu tiên, ta khai báo mảng 2 chiều (Đây là mảng chưa thông số điểm của từng thành viên hoạt động)
|Cột thứ 1|Cột thứ 2|Cột thứ 3|
|Id User |Điểm |Tên User|
+ Chạy Json để thu về Id post của từng bài để đưa vào khâu xử lý (như id user post bài, id user reactions stt + số lượng reactions , id user cmt, id user share + số lượng share. Tất cả, mình để chia thành từng function nhỏ, cho đỡ rối trong khi code và trả giá trị ra là mảng). Đồng thời lấy giá trị Updated_time để thống kê theo ngày giờ (làm biến Limit Time, ví dụ : Thống kê trong 30 ngày, 1 tuần hay 1 ngày chẳng hạn,...)
+ Sau khi có được mảng user reaction, cmt, share, ta sẽ thực hiện cộng điểm cho từng user reaction, cmt, share ấy dựa trên id
* Chạy vòng lập For -> Số lượng mảng()
* Kiểm tra trùng
Nếu không có thì add id đó vào danh sách ranking với point là 1 (like) hay 2 (share) tùy vào số điểm chẳng hạn
Nếu có thì cộng dồn điểm đó vào vị trí trùng tìm được
+ Tiếp theo, ta lấy ID của người post và tiến hành add vào danh sách (giống như cách kiểm tra trùng trên)
+ Trong lúc chạy, nếu Updated_time vẫn lớn hơn Limit Time (Limit time là thời gian thống kê trước đó, như đã nói trên) thì cứ chạy, ngược lại thì thoát khỏi quá trình chạy Json
+ Chắc chắn Api facebook sẽ tự động phân thành trang với dạng Json là : ["paging"]["next"], lúc này, bạn thực hiện đệ quy :
* Nếu Updated_time vẫn lớn hơn Limit Time thì ta lấy link next phía trên và tiến hành gọi lại hàm, để tiếp tục cộng dồn vào hệ thống ranking ( hàm có dạng _ham(ByRef $link, ....)
+ Cuối cùng, ta tiến hành sắp xếp giảm dần theo giá trị điểm trong mảng 2 chiều
=> Vậy là ta đã có được một hệ thống ranking hoàn chỉnh về số điểm của từng thành viên rồi nhé ^_^ ! Nếu bạn nào giỏi thì có thể ra thuật toán ngon hơn của mình, và share cho mọi người nha, hoặc cmt bên dưới bài viết, để mình cập nhập thêm cho Bài viết này.
V. Viết code Đầu tiên, ta tạo biến $LimitTime
$LimitTime = _DateDiff('s', "1970/01/01 00:00:00", _NowCalc()) ; Lấy time hiện tại (convert to seconds)
$ngay = 86400 ; tổng giây một ngày
$tuan = 604800 ; tổng giây một tuần
$thang = 2592000 ; tổng giây một tháng
$LimitTime = $LimitTime-$ngay ; Vd : thống kê trong một ngày
Hàm
_FormatTime()
do mình viết dựa trên time mà Api facebook cung cấp (dùng để chuyển đối chuỗi time thành tổng giây)Func _FormatTime($string)
$string = StringReplace($string, "T", " ")
$string = StringReplace($string, "+0000", "")
$string = StringReplace($string, "-", "/")
$time = _DateDiff('s', "1970/01/01 00:00:00", $string)
Return $time
EndFunc
Hàm đệ quy để tiến hành chạy Ranking
Func _GetPost2($access_token,ByRef $link, $LimitTime)
$JsonObj = Json_Decode(_INetGetSource($link))
If @error then Return SetError(1,0,0)
$i = 0
$point = 0
While 1
$point = 0
$updated_time = Json_Get($JsonObj, '["data"][' & $i & ']["updated_time"]')
If @error then ExitLoop
If _FOrmatTime($updated_time)<$LimitTime Then ExitLoop
$actor_id = Json_Get($JsonObj, '["data"][' & $i & ']["from"]["id"]')
If @error then ExitLoop
$point += 3
$post_id = Json_Get($JsonObj, '["data"][' & $i & ']["id"]')
If @error then ExitLoop
ConsoleWrite($post_id&@CRLF)
$sharecount = _GetShare($post_id, $access_token)
If $sharecount <> False then $point += $sharecount
$linkReactions = "https://graph.facebook.com/v2.8/"&$post_id&"/reactions?limit=25&access_token="&$access_token
Global $Array[0]
_GetReactions($linkReactions)
If Not IsArray($Array) Then
_ArrayAdd($Array2d, $actor_id&"|1") ; Nếu không có ai like, sẽ tự động tăng điểm +1 cho người đăng bài
Else
$point += Ubound($Array) ; Tăng điểm cho người đăng bài dựa trên số lượng like
EndIf ;
Lọc Trùng Sau khi thêm Reactions
For $j = 0 To (UBound($Array)-1)
$tam = _ArrayFindAll($Array2d, $Array[$j], Default, Default, Default, Default, 0) ; Lọc Trùng của ID Người like trong Danh Sách Ranking
If UBound($tam)>=1 Then
$Array2d[$tam[0]][1] += 1 ; Nếu trùng thì cộng dồn điểm cho user id (+1)
Else
_ArrayAdd($Array2d, $Array[$j]&"|1") ; Nếu không có trùng thì tạo user id mới cho Array
EndIf
Next
$linkCMT = "https://graph.facebook.com/v2.8/"&$post_id&"?fields=comments&access_token="&$access_token
Global $ArrayCMT[0]
_GetCMT($linkCMT)
If Not IsArray($ArrayCMT) Then
_ArrayAdd($Array2d, $actor_id&"|1") ;Nếu không có ai cmt, sẽ tự động tăng điểm +1 cho người đăng bài
Else
$point += Ubound($ArrayCMT);Tăng điểm cho người đăng bài dựa trên số lượng cmt
EndIf
For $j = 0 To (UBound($ArrayCMT)-1)
$tam = _ArrayFindAll($Array2d, $ArrayCMT[$j], Default, Default, Default, Default, 0);Lọc Trùng của ID Người CMT trong Danh Sách Ranking
If UBound($tam)>=1 Then
$Array2d[$tam[0]][1] += 1; Nếu trùng thì cộng dồn điểm cho user id (+1)
Else
_ArrayAdd($Array2d, $ArrayCMT[$j]&"|1");Nếu không có trùng thì tạo user id mới cho Array
EndIf
Next ;
Lọc Trùng để thêm vào danh sách Ranking đối với người đăng bài
$tam = _ArrayFindAll($Array2d, $actor_id, Default, Default, Default, Default, 0) ; Kiểm tra xem id người đăng bài có trong danh sách Ranking hay không?
If UBound($tam)=1 Then
$Array2d[$tam[0]][1] += $point ; Nếu trùng thì cộng dồn điểm
Else
_ArrayAdd($Array2d, $actor_id&"|"&$point) ;Nếu không trùng thì tạo user id
EndIf
$updated_time = Json_Get($JsonObj, '["data"][' & $i & ']["updated_time"]') ; Lấy Update time để kiểm tra Limit Time
$i += 1
WEnd
If _FOrmatTime($updated_time)<$LimitTime Then
Return 1
Else
$updated_time = Json_Get($JsonObj, '["data"][' & $i-1 & ']["updated_time"]')
If @error then Return SetError(1,0,0)
If $updated_time<=$LimitTime Then
Return 1
Else
$link = Json_Get($JsonObj, '["paging"]["next"]') ; Lấy link kế tiếp của api để get tiếp
If $link<>"" then
_GetPost2($access_token, $link, $LimitTime) ; Gọi đệ quy để cộng dồn
Else
Return 1
EndIf
EndIf
EndIf
EndFunc
Cách gọi hàm đệ quy ra :
Global $Array2d[0][3]
$access_token="Token của bạn"
$id_group = "id group";Vd : 364997627165697
$link = "https://graph.facebook.com/v2.8/"&$id_group&"/feed?fields=from,updated_time&access_token="&$access_token
_GetPost2($access_token, $link, $LimitTime)
Sau khi gọi hàm đó xong, ta tiến hành get tên cho từng id với lệnh sau :
_ArraySort($Array2d,1,0,0,1); Sắp xếp điểm point theo thứ tự giảm dần
FOr $i=0 to UBound($Array2d, 1)-1
$Array2d[$i][2] = _GetName($Array2d[$i][0], $access_token); Lấy tên của id
ConsoleWrite($Array2d[$i][2]&@CRLF); Write tên ra
Next
Trong đó có hàm _GetName()
Func _GetName($id, $access_token)
$link = "https://graph.facebook.com/v2.8/"&$id&"?access_token=" & $access_token
$JsonObj = Json_Decode(_INetGetSource($link))
$name = Json_Get($JsonObj, '["name"]')
Return $name
EndFunc
Lấy user reactions từ ID Post
Func _GetReactions(ByRef $link)
If $link="" then Return SetError(1,0,0)
$JsonObj = Json_Decode(_INetGetSource($link))
$i = 0
While 1
$id = Json_Get($JsonObj, '["data"][' & $i & ']["id"]')
If @error then ExitLoop
_ArrayAdd($Array, $id)
$i += 1
Wend
$next = Json_Get($JsonObj, '["paging"]["next"]')
If @error Then Return $Array
If $next<>"" and not @error Then
_GetReactions($next); Gọi đệ quy
EndIf
Return $Array
EndFunc
Lấy comment từ ID Post
Func _GetCMT(ByRef $link)
If $link="" then Return SetError(1,0,0)
$JsonObj = Json_Decode(_INetGetSource($link))
$i = 0
While 1
$id = Json_Get($JsonObj, '["comments"]["data"][' & $i & ']["from"]["id"]')
If @error then ExitLoop
_ArrayAdd($ArrayCMT, $id)
$i += 1
Wend
$next = Json_Get($JsonObj, '["paging"]["next"]')
If @error Then Return $ArrayCMT
If $next<>"" and not @error Then
_GetCMT($next); Gọi đệ quy
EndIf
Return $ArrayCMT
EndFunc
Lấy số lựợng share từ ID Post
Func _GetShare($id, $access_token)
If StringInStr($id, "_")=0 or $id="" or $access_token="" then Return SetError(1,0,False)
$link = "https://graph.facebook.com/v2.8/"&$id&"?fields=shares&access_token=" & $access_token
$JsonObj = Json_Decode(_INetGetSource($link))
$count = Json_Get($JsonObj, '["shares"]["count"]')
ConsoleWrite($count&@CRLF)
Return $count
EndFunc
Link DownLoad Full UDF (AutoIT) : https://github.com/nguyenphucbao68/Ranking-Members-In-Group
VI. Kết quả Test code trong vòng 1 tuần đối với group J2Team
Thời gian chạy code : 18 phút 1 giây (hao nhất ở phần GetName, tốn 16 phút, nếu bạn nào có ý tưởng thì cứ cmt bên dưới nha, mình sẽ bổ sung vào bài của mình nếu thấy hợp lí >.< )
Thu được 1332 id user và số điểm tương ứng ! Thánh Lâm Oscar rank cao vl =.=
VII. Đôi lời Các bạn có thể copy, có thể phát triển code và share, nhưng mình mong các bạn ghi rõ nguồn người viết ^^, nếu bạn sử dụng lõi cũ và thuật toán như code mình.
Nguồn (Tác giả): https://www.facebook.com/trojannguyen.dev