Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc
Commits
052ce0ee
Commit
052ce0ee
authored
Jul 31, 2011
by
Rafaël Carré
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
audioscrobbler: reorder functions to remove declarations
parent
b357472a
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
394 additions
and
405 deletions
+394
-405
modules/misc/audioscrobbler.c
modules/misc/audioscrobbler.c
+394
-405
No files found.
modules/misc/audioscrobbler.c
View file @
052ce0ee
...
...
@@ -115,18 +115,6 @@ static int Open ( vlc_object_t * );
static
void
Close
(
vlc_object_t
*
);
static
void
Run
(
intf_thread_t
*
);
static
int
ItemChange
(
vlc_object_t
*
,
const
char
*
,
vlc_value_t
,
vlc_value_t
,
void
*
);
static
int
PlayingChange
(
vlc_object_t
*
,
const
char
*
,
vlc_value_t
,
vlc_value_t
,
void
*
);
static
void
AddToQueue
(
intf_thread_t
*
);
static
int
Handshake
(
intf_thread_t
*
);
static
void
ReadMetaData
(
intf_thread_t
*
);
static
void
DeleteSong
(
audioscrobbler_song_t
*
);
static
int
ParseURL
(
char
*
,
char
**
,
char
**
,
int
*
);
static
void
HandleInterval
(
mtime_t
*
,
unsigned
int
*
);
/*****************************************************************************
* Module descriptor
****************************************************************************/
...
...
@@ -173,287 +161,178 @@ vlc_module_begin ()
vlc_module_end
()
/*****************************************************************************
*
Open: initialize and create stuff
*
DeleteSong : Delete the char pointers in a song
*****************************************************************************/
static
int
Open
(
vlc_object_t
*
p_this
)
static
void
DeleteSong
(
audioscrobbler_song_t
*
p_song
)
{
intf_thread_t
*
p_intf
=
(
intf_thread_t
*
)
p_this
;
intf_sys_t
*
p_sys
=
calloc
(
1
,
sizeof
(
intf_sys_t
)
);
FREENULL
(
p_song
->
psz_a
);
FREENULL
(
p_song
->
psz_b
);
FREENULL
(
p_song
->
psz_t
);
FREENULL
(
p_song
->
psz_m
);
FREENULL
(
p_song
->
psz_n
);
}
if
(
!
p_sys
)
return
VLC_ENOMEM
;
/*****************************************************************************
* ReadMetaData : Read meta data when parsed by vlc
*****************************************************************************/
static
void
ReadMetaData
(
intf_thread_t
*
p_this
)
{
input_thread_t
*
p_input
;
input_item_t
*
p_item
;
p_intf
->
p_sys
=
p_sys
;
intf_sys_t
*
p_sys
=
p_this
->
p_sys
;
vlc_mutex_init
(
&
p_sys
->
lock
);
vlc_cond_init
(
&
p_sys
->
wait
);
p_input
=
playlist_CurrentInput
(
pl_Get
(
p_this
)
);
if
(
!
p_input
)
return
;
var_AddCallback
(
pl_Get
(
p_intf
),
"item-current"
,
ItemChange
,
p_intf
);
p_item
=
input_GetItem
(
p_input
);
if
(
!
p_item
)
{
vlc_object_release
(
p_input
);
return
;
}
p_intf
->
pf_run
=
Run
;
#define ALLOC_ITEM_META( a, b ) do { \
char *psz_meta = input_item_Get##b( p_item ); \
if( psz_meta && *psz_meta ) \
a = encode_URI_component( psz_meta ); \
free( psz_meta ); \
} while(0)
return
VLC_SUCCESS
;
}
vlc_mutex_lock
(
&
p_sys
->
lock
);
/*****************************************************************************
* Close: destroy interface stuff
*****************************************************************************/
static
void
Close
(
vlc_object_t
*
p_this
)
{
playlist_t
*
p_playlist
=
pl_Get
(
p_this
);
input_thread_t
*
p_input
;
intf_thread_t
*
p_intf
=
(
intf_thread_t
*
)
p_this
;
intf_sys_t
*
p_sys
=
p_intf
->
p_sys
;
p_sys
->
b_meta_read
=
true
;
var_DelCallback
(
p_playlist
,
"item-current"
,
ItemChange
,
p_intf
);
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_a
,
Artist
);
if
(
!
p_sys
->
p_current_song
.
psz_a
)
{
msg_Dbg
(
p_this
,
"No artist.."
);
DeleteSong
(
&
p_sys
->
p_current_song
);
goto
end
;
}
p_input
=
playlist_CurrentInput
(
p_playlist
);
if
(
p_inpu
t
)
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_t
,
Title
);
if
(
!
p_sys
->
p_current_song
.
psz_
t
)
{
if
(
p_sys
->
b_state_cb
)
var_DelCallback
(
p_input
,
"intf-event"
,
PlayingChange
,
p_intf
);
vlc_object_release
(
p_input
)
;
msg_Dbg
(
p_this
,
"No track name.."
);
DeleteSong
(
&
p_sys
->
p_current_song
);
goto
end
;
}
int
i
;
for
(
i
=
0
;
i
<
p_sys
->
i_songs
;
i
++
)
DeleteSong
(
&
p_sys
->
p_queue
[
i
]
);
free
(
p_sys
->
psz_submit_host
);
free
(
p_sys
->
psz_submit_file
);
#if 0 //NOT USED
free( p_sys->psz_nowp_host );
free( p_sys->psz_nowp_file );
#endif
vlc_cond_destroy
(
&
p_sys
->
wait
);
vlc_mutex_destroy
(
&
p_sys
->
lock
);
free
(
p_sys
);
}
/* Now we have read the mandatory meta data, so we can submit that info */
p_sys
->
b_submit
=
true
;
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_b
,
Album
);
if
(
!
p_sys
->
p_current_song
.
psz_b
)
p_sys
->
p_current_song
.
psz_b
=
calloc
(
1
,
1
);
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_m
,
TrackID
);
if
(
!
p_sys
->
p_current_song
.
psz_m
)
p_sys
->
p_current_song
.
psz_m
=
calloc
(
1
,
1
);
p_sys
->
p_current_song
.
i_l
=
input_item_GetDuration
(
p_item
)
/
1000000
;
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_n
,
TrackNum
);
if
(
!
p_sys
->
p_current_song
.
psz_n
)
p_sys
->
p_current_song
.
psz_n
=
calloc
(
1
,
1
);
#undef ALLOC_ITEM_META
msg_Dbg
(
p_this
,
"Meta data registered"
);
end:
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_object_release
(
p_input
);
}
/*****************************************************************************
*
Run : call Handshake() then submit songs
*
AddToQueue: Add the played song to the queue to be submitted
*****************************************************************************/
static
void
Run
(
intf_thread_t
*
p_intf
)
static
void
AddToQueue
(
intf_thread_t
*
p_this
)
{
char
*
psz_submit
,
*
psz_submit_song
,
*
psz_submit_tmp
;
int
i_net_ret
;
int
i_song
;
uint8_t
p_buffer
[
1024
];
char
*
p_buffer_pos
;
int
i_post_socket
;
int
canc
=
vlc_savecancel
();
mtime_t
played_time
;
intf_sys_t
*
p_sys
=
p_this
->
p_sys
;
intf_sys_t
*
p_sys
=
p_intf
->
p_sys
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
if
(
!
p_sys
->
b_submit
)
goto
end
;
/*
main loop
*/
for
(
;;
)
{
bool
b_wait
=
false
;
/*
wait for the user to listen enough before submitting
*/
played_time
=
mdate
()
-
p_sys
->
p_current_song
.
i_start
-
p_sys
->
time_total_pauses
;
played_time
/=
1000000
;
/* µs → s */
/*HACK: it seam that the preparsing sometime fail,
so use the playing time as the song length */
if
(
p_sys
->
p_current_song
.
i_l
==
0
)
p_sys
->
p_current_song
.
i_l
=
played_time
;
vlc_restorecancel
(
canc
);
vlc_mutex_lock
(
&
p_sys
->
lock
);
mutex_cleanup_push
(
&
p_sys
->
lock
);
/* Don't send song shorter than 30s */
if
(
p_sys
->
p_current_song
.
i_l
<
30
)
{
msg_Dbg
(
p_this
,
"Song too short (< 30s), not submitting"
);
goto
end
;
}
if
(
mdate
()
<
p_sys
->
next_exchange
)
/* wait until we can resubmit, i.e. */
b_wait
=
vlc_cond_timedwait
(
&
p_sys
->
wait
,
&
p_sys
->
lock
,
p_sys
->
next_exchange
)
==
0
;
else
/* wait for data to submit */
/* we are signaled each time there is a song to submit */
vlc_cond_wait
(
&
p_sys
->
wait
,
&
p_sys
->
lock
);
vlc_cleanup_run
();
canc
=
vlc_savecancel
();
/* Send if the user had listen more than 240s OR half the track length */
if
(
(
played_time
<
240
)
&&
(
played_time
<
(
p_sys
->
p_current_song
.
i_l
/
2
)
)
)
{
msg_Dbg
(
p_this
,
"Song not listened long enough, not submitting"
);
goto
end
;
}
if
(
b_wait
)
continue
;
/* holding on until next_exchange */
/* Check that all meta are present */
if
(
!
p_sys
->
p_current_song
.
psz_a
||
!*
p_sys
->
p_current_song
.
psz_a
||
!
p_sys
->
p_current_song
.
psz_t
||
!*
p_sys
->
p_current_song
.
psz_t
)
{
msg_Dbg
(
p_this
,
"Missing artist or title, not submitting"
);
goto
end
;
}
/* handshake if needed */
if
(
!
p_sys
->
b_handshaked
)
{
msg_Dbg
(
p_intf
,
"Handshaking with last.fm ..."
);
if
(
p_sys
->
i_songs
>=
QUEUE_MAX
)
{
msg_Warn
(
p_this
,
"Submission queue is full, not submitting"
);
goto
end
;
}
switch
(
Handshake
(
p_intf
)
)
{
case
VLC_ENOMEM
:
return
;
msg_Dbg
(
p_this
,
"Song will be submitted."
);
case
VLC_ENOVAR
:
/* username not set */
dialog_Fatal
(
p_intf
,
_
(
"Last.fm username not set"
),
"%s"
,
_
(
"Please set a username or disable the "
"audioscrobbler plugin, and restart VLC.
\n
"
"Visit http://www.last.fm/join/ to get an account."
)
);
return
;
#define QUEUE_COPY( a ) \
p_sys->p_queue[p_sys->i_songs].a = p_sys->p_current_song.a
case
VLC_SUCCESS
:
msg_Dbg
(
p_intf
,
"Handshake successfull :)"
);
p_sys
->
b_handshaked
=
true
;
p_sys
->
i_interval
=
0
;
p_sys
->
next_exchange
=
mdate
();
break
;
#define QUEUE_COPY_NULL( a ) \
QUEUE_COPY( a ); \
p_sys->p_current_song.a = NULL
case
VLC_AUDIOSCROBBLER_EFATAL
:
msg_Warn
(
p_intf
,
"Exiting..."
);
return
;
QUEUE_COPY
(
i_l
);
QUEUE_COPY_NULL
(
psz_n
);
QUEUE_COPY_NULL
(
psz_a
);
QUEUE_COPY_NULL
(
psz_t
);
QUEUE_COPY_NULL
(
psz_b
);
QUEUE_COPY_NULL
(
psz_m
);
QUEUE_COPY
(
date
);
#undef QUEUE_COPY_NULL
#undef QUEUE_COPY
case
VLC_EGENERIC
:
default:
/* protocol error : we'll try later */
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
break
;
}
/* if handshake failed let's restart the loop */
if
(
!
p_sys
->
b_handshaked
)
continue
;
}
p_sys
->
i_songs
++
;
msg_Dbg
(
p_intf
,
"Going to submit some data..."
);
/* signal the main loop we have something to submit */
vlc_cond_signal
(
&
p_sys
->
wait
);
/* The session may be invalid if there is a trailing \n */
char
*
psz_ln
=
strrchr
(
p_sys
->
psz_auth_token
,
'\n'
);
if
(
psz_ln
)
*
psz_ln
=
'\0'
;
end:
DeleteSong
(
&
p_sys
->
p_current_song
);
p_sys
->
b_submit
=
false
;
vlc_mutex_unlock
(
&
p_sys
->
lock
);
}
if
(
!
asprintf
(
&
psz_submit
,
"s=%s"
,
p_sys
->
psz_auth_token
)
)
{
/* Out of memory */
return
;
}
/* forge the HTTP POST request */
vlc_mutex_lock
(
&
p_sys
->
lock
);
audioscrobbler_song_t
*
p_song
;
for
(
i_song
=
0
;
i_song
<
p_sys
->
i_songs
;
i_song
++
)
{
p_song
=
&
p_sys
->
p_queue
[
i_song
];
if
(
!
asprintf
(
&
psz_submit_song
,
"&a%%5B%d%%5D=%s"
"&t%%5B%d%%5D=%s"
"&i%%5B%d%%5D=%u"
"&o%%5B%d%%5D=P"
"&r%%5B%d%%5D="
"&l%%5B%d%%5D=%d"
"&b%%5B%d%%5D=%s"
"&n%%5B%d%%5D=%s"
"&m%%5B%d%%5D=%s"
,
i_song
,
p_song
->
psz_a
,
i_song
,
p_song
->
psz_t
,
i_song
,
(
unsigned
)
p_song
->
date
,
/* HACK: %ju (uintmax_t) unsupported on Windows */
i_song
,
i_song
,
i_song
,
p_song
->
i_l
,
i_song
,
p_song
->
psz_b
,
i_song
,
p_song
->
psz_n
,
i_song
,
p_song
->
psz_m
)
)
{
/* Out of memory */
vlc_mutex_unlock
(
&
p_sys
->
lock
);
return
;
}
psz_submit_tmp
=
psz_submit
;
if
(
!
asprintf
(
&
psz_submit
,
"%s%s"
,
psz_submit_tmp
,
psz_submit_song
)
)
{
/* Out of memory */
free
(
psz_submit_tmp
);
free
(
psz_submit_song
);
vlc_mutex_unlock
(
&
p_sys
->
lock
);
return
;
}
free
(
psz_submit_song
);
free
(
psz_submit_tmp
);
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
i_post_socket
=
net_ConnectTCP
(
p_intf
,
p_sys
->
psz_submit_host
,
p_sys
->
i_submit_port
);
if
(
i_post_socket
==
-
1
)
{
/* If connection fails, we assume we must handshake again */
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
p_sys
->
b_handshaked
=
false
;
free
(
psz_submit
);
continue
;
}
/* we transmit the data */
i_net_ret
=
net_Printf
(
p_intf
,
i_post_socket
,
NULL
,
POST_REQUEST
,
p_sys
->
psz_submit_file
,
(
unsigned
)
strlen
(
psz_submit
),
p_sys
->
psz_submit_host
,
VERSION
,
psz_submit
);
free
(
psz_submit
);
if
(
i_net_ret
==
-
1
)
{
/* If connection fails, we assume we must handshake again */
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
p_sys
->
b_handshaked
=
false
;
continue
;
}
i_net_ret
=
net_Read
(
p_intf
,
i_post_socket
,
NULL
,
p_buffer
,
1023
,
false
);
if
(
i_net_ret
<=
0
)
{
/* if we get no answer, something went wrong : try again */
continue
;
}
net_Close
(
i_post_socket
);
p_buffer
[
i_net_ret
]
=
'\0'
;
p_buffer_pos
=
strstr
(
(
char
*
)
p_buffer
,
"FAILED"
);
if
(
p_buffer_pos
)
{
msg_Warn
(
p_intf
,
"%s"
,
p_buffer_pos
);
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
continue
;
}
p_buffer_pos
=
strstr
(
(
char
*
)
p_buffer
,
"BADSESSION"
);
if
(
p_buffer_pos
)
{
msg_Err
(
p_intf
,
"Authentication failed (BADSESSION), are you connected to last.fm with another program ?"
);
p_sys
->
b_handshaked
=
false
;
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
continue
;
}
p_buffer_pos
=
strstr
(
(
char
*
)
p_buffer
,
"OK"
);
if
(
p_buffer_pos
)
{
int
i
;
for
(
i
=
0
;
i
<
p_sys
->
i_songs
;
i
++
)
DeleteSong
(
&
p_sys
->
p_queue
[
i
]
);
p_sys
->
i_songs
=
0
;
p_sys
->
i_interval
=
0
;
p_sys
->
next_exchange
=
mdate
();
msg_Dbg
(
p_intf
,
"Submission successful!"
);
}
else
{
msg_Err
(
p_intf
,
"Authentication failed, handshaking again (%s)"
,
p_buffer
);
p_sys
->
b_handshaked
=
false
;
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
continue
;
}
}
vlc_restorecancel
(
canc
);
}
/*****************************************************************************
* PlayingChange: Playing status change callback
*****************************************************************************/
static
int
PlayingChange
(
vlc_object_t
*
p_this
,
const
char
*
psz_var
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
{
VLC_UNUSED
(
oldval
);
/*****************************************************************************
* PlayingChange: Playing status change callback
*****************************************************************************/
static
int
PlayingChange
(
vlc_object_t
*
p_this
,
const
char
*
psz_var
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
{
VLC_UNUSED
(
oldval
);
intf_thread_t
*
p_intf
=
(
intf_thread_t
*
)
p_data
;
intf_sys_t
*
p_sys
=
p_intf
->
p_sys
;
...
...
@@ -549,86 +428,63 @@ static int ItemChange( vlc_object_t *p_this, const char *psz_var,
}
/*****************************************************************************
*
AddToQueue: Add the played song to the queue to be submitted
*
Open: initialize and create stuff
*****************************************************************************/
static
void
AddToQueue
(
intf_thread
_t
*
p_this
)
static
int
Open
(
vlc_object
_t
*
p_this
)
{
mtime_t
played_time
;
intf_sys_t
*
p_sys
=
p_this
->
p_sys
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
if
(
!
p_sys
->
b_submit
)
goto
end
;
/* wait for the user to listen enough before submitting */
played_time
=
mdate
()
-
p_sys
->
p_current_song
.
i_start
-
p_sys
->
time_total_pauses
;
played_time
/=
1000000
;
/* µs → s */
/*HACK: it seam that the preparsing sometime fail,
so use the playing time as the song length */
if
(
p_sys
->
p_current_song
.
i_l
==
0
)
p_sys
->
p_current_song
.
i_l
=
played_time
;
/* Don't send song shorter than 30s */
if
(
p_sys
->
p_current_song
.
i_l
<
30
)
{
msg_Dbg
(
p_this
,
"Song too short (< 30s), not submitting"
);
goto
end
;
}
intf_thread_t
*
p_intf
=
(
intf_thread_t
*
)
p_this
;
intf_sys_t
*
p_sys
=
calloc
(
1
,
sizeof
(
intf_sys_t
)
);
/* Send if the user had listen more than 240s OR half the track length */
if
(
(
played_time
<
240
)
&&
(
played_time
<
(
p_sys
->
p_current_song
.
i_l
/
2
)
)
)
{
msg_Dbg
(
p_this
,
"Song not listened long enough, not submitting"
);
goto
end
;
}
if
(
!
p_sys
)
return
VLC_ENOMEM
;
/* Check that all meta are present */
if
(
!
p_sys
->
p_current_song
.
psz_a
||
!*
p_sys
->
p_current_song
.
psz_a
||
!
p_sys
->
p_current_song
.
psz_t
||
!*
p_sys
->
p_current_song
.
psz_t
)
{
msg_Dbg
(
p_this
,
"Missing artist or title, not submitting"
);
goto
end
;
}
p_intf
->
p_sys
=
p_sys
;
if
(
p_sys
->
i_songs
>=
QUEUE_MAX
)
{
msg_Warn
(
p_this
,
"Submission queue is full, not submitting"
);
goto
end
;
}
vlc_mutex_init
(
&
p_sys
->
lock
);
vlc_cond_init
(
&
p_sys
->
wait
);
msg_Dbg
(
p_this
,
"Song will be submitted."
);
var_AddCallback
(
pl_Get
(
p_intf
),
"item-current"
,
ItemChange
,
p_intf
);
#define QUEUE_COPY( a ) \
p_sys->p_queue[p_sys->i_songs].a = p_sys->p_current_song.a
p_intf
->
pf_run
=
Run
;
#define QUEUE_COPY_NULL( a ) \
QUEUE_COPY( a ); \
p_sys->p_current_song.a = NULL
return
VLC_SUCCESS
;
}
QUEUE_COPY
(
i_l
);
QUEUE_COPY_NULL
(
psz_n
);
QUEUE_COPY_NULL
(
psz_a
);
QUEUE_COPY_NULL
(
psz_t
);
QUEUE_COPY_NULL
(
psz_b
);
QUEUE_COPY_NULL
(
psz_m
);
QUEUE_COPY
(
date
)
;
#undef QUEUE_COPY_NULL
#undef QUEUE_COPY
/*****************************************************************************
* Close: destroy interface stuff
*****************************************************************************/
static
void
Close
(
vlc_object_t
*
p_this
)
{
playlist_t
*
p_playlist
=
pl_Get
(
p_this
);
input_thread_t
*
p_input
;
intf_thread_t
*
p_intf
=
(
intf_thread_t
*
)
p_this
;
intf_sys_t
*
p_sys
=
p_intf
->
p_sys
;
p_sys
->
i_songs
++
;
var_DelCallback
(
p_playlist
,
"item-current"
,
ItemChange
,
p_intf
)
;
/* signal the main loop we have something to submit */
vlc_cond_signal
(
&
p_sys
->
wait
);
p_input
=
playlist_CurrentInput
(
p_playlist
);
if
(
p_input
)
{
if
(
p_sys
->
b_state_cb
)
var_DelCallback
(
p_input
,
"intf-event"
,
PlayingChange
,
p_intf
);
vlc_object_release
(
p_input
);
}
end:
DeleteSong
(
&
p_sys
->
p_current_song
);
p_sys
->
b_submit
=
false
;
vlc_mutex_unlock
(
&
p_sys
->
lock
);
int
i
;
for
(
i
=
0
;
i
<
p_sys
->
i_songs
;
i
++
)
DeleteSong
(
&
p_sys
->
p_queue
[
i
]
);
free
(
p_sys
->
psz_submit_host
);
free
(
p_sys
->
psz_submit_file
);
#if 0 //NOT USED
free( p_sys->psz_nowp_host );
free( p_sys->psz_nowp_file );
#endif
vlc_cond_destroy
(
&
p_sys
->
wait
);
vlc_mutex_destroy
(
&
p_sys
->
lock
);
free
(
p_sys
);
}
/*****************************************************************************
* ParseURL : Split an http:// URL into host, file, and port
*
...
...
@@ -912,105 +768,238 @@ proto:
return
VLC_EGENERIC
;
}
/*****************************************************************************
* DeleteSong : Delete the char pointers in a song
*****************************************************************************/
static
void
DeleteSong
(
audioscrobbler_song_t
*
p_song
)
{
FREENULL
(
p_song
->
psz_a
);
FREENULL
(
p_song
->
psz_b
);
FREENULL
(
p_song
->
psz_t
);
FREENULL
(
p_song
->
psz_m
);
FREENULL
(
p_song
->
psz_n
);
}
/*****************************************************************************
* ReadMetaData : Read meta data when parsed by vlc
*****************************************************************************/
static
void
ReadMetaData
(
intf_thread_t
*
p_this
)
static
void
HandleInterval
(
mtime_t
*
next
,
unsigned
int
*
i_interval
)
{
input_thread_t
*
p_input
;
input_item_t
*
p_item
;
if
(
*
i_interval
==
0
)
{
/* first interval is 1 minute */
*
i_interval
=
1
;
}
else
{
/* else we double the previous interval, up to 120 minutes */
*
i_interval
<<=
1
;
if
(
*
i_interval
>
120
)
*
i_interval
=
120
;
}
*
next
=
mdate
()
+
(
*
i_interval
*
1000000
*
60
);
}
intf_sys_t
*
p_sys
=
p_this
->
p_sys
;
/*****************************************************************************
* Run : call Handshake() then submit songs
*****************************************************************************/
static
void
Run
(
intf_thread_t
*
p_intf
)
{
char
*
psz_submit
,
*
psz_submit_song
,
*
psz_submit_tmp
;
int
i_net_ret
;
int
i_song
;
uint8_t
p_buffer
[
1024
];
char
*
p_buffer_pos
;
int
i_post_socket
;
int
canc
=
vlc_savecancel
();
p_input
=
playlist_CurrentInput
(
pl_Get
(
p_this
)
);
if
(
!
p_input
)
return
;
intf_sys_t
*
p_sys
=
p_intf
->
p_sys
;
p_item
=
input_GetItem
(
p_input
);
if
(
!
p_item
)
/* main loop */
for
(
;;
)
{
vlc_object_release
(
p_input
);
return
;
}
bool
b_wait
=
false
;
#define ALLOC_ITEM_META( a, b ) do { \
char *psz_meta = input_item_Get##b( p_item ); \
if( psz_meta && *psz_meta ) \
a = encode_URI_component( psz_meta ); \
free( psz_meta ); \
} while(0)
vlc_mutex_lock
(
&
p_sys
->
lock
);
vlc_restorecancel
(
canc
);
vlc_mutex_lock
(
&
p_sys
->
lock
);
mutex_cleanup_push
(
&
p_sys
->
lock
);
p_sys
->
b_meta_read
=
true
;
if
(
mdate
()
<
p_sys
->
next_exchange
)
/* wait until we can resubmit, i.e. */
b_wait
=
vlc_cond_timedwait
(
&
p_sys
->
wait
,
&
p_sys
->
lock
,
p_sys
->
next_exchange
)
==
0
;
else
/* wait for data to submit */
/* we are signaled each time there is a song to submit */
vlc_cond_wait
(
&
p_sys
->
wait
,
&
p_sys
->
lock
);
vlc_cleanup_run
();
canc
=
vlc_savecancel
();
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_a
,
Artist
);
if
(
!
p_sys
->
p_current_song
.
psz_a
)
{
msg_Dbg
(
p_this
,
"No artist.."
);
DeleteSong
(
&
p_sys
->
p_current_song
);
goto
end
;
}
if
(
b_wait
)
continue
;
/* holding on until next_exchange */
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_t
,
Title
);
if
(
!
p_sys
->
p_current_song
.
psz_t
)
{
msg_Dbg
(
p_this
,
"No track name.."
);
DeleteSong
(
&
p_sys
->
p_current_song
);
goto
end
;
}
/* handshake if needed */
if
(
!
p_sys
->
b_handshaked
)
{
msg_Dbg
(
p_intf
,
"Handshaking with last.fm ..."
);
/* Now we have read the mandatory meta data, so we can submit that info */
p_sys
->
b_submit
=
true
;
switch
(
Handshake
(
p_intf
)
)
{
case
VLC_ENOMEM
:
return
;
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_b
,
Album
);
if
(
!
p_sys
->
p_current_song
.
psz_b
)
p_sys
->
p_current_song
.
psz_b
=
calloc
(
1
,
1
);
case
VLC_ENOVAR
:
/* username not set */
dialog_Fatal
(
p_intf
,
_
(
"Last.fm username not set"
),
"%s"
,
_
(
"Please set a username or disable the "
"audioscrobbler plugin, and restart VLC.
\n
"
"Visit http://www.last.fm/join/ to get an account."
)
);
return
;
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_m
,
TrackID
);
if
(
!
p_sys
->
p_current_song
.
psz_m
)
p_sys
->
p_current_song
.
psz_m
=
calloc
(
1
,
1
);
case
VLC_SUCCESS
:
msg_Dbg
(
p_intf
,
"Handshake successfull :)"
);
p_sys
->
b_handshaked
=
true
;
p_sys
->
i_interval
=
0
;
p_sys
->
next_exchange
=
mdate
();
break
;
p_sys
->
p_current_song
.
i_l
=
input_item_GetDuration
(
p_item
)
/
1000000
;
case
VLC_AUDIOSCROBBLER_EFATAL
:
msg_Warn
(
p_intf
,
"Exiting..."
);
return
;
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_n
,
TrackNum
);
if
(
!
p_sys
->
p_current_song
.
psz_n
)
p_sys
->
p_current_song
.
psz_n
=
calloc
(
1
,
1
);
#undef ALLOC_ITEM_META
case
VLC_EGENERIC
:
default:
/* protocol error : we'll try later */
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
break
;
}
/* if handshake failed let's restart the loop */
if
(
!
p_sys
->
b_handshaked
)
continue
;
}
msg_Dbg
(
p_this
,
"Meta data registered
"
);
msg_Dbg
(
p_intf
,
"Going to submit some data...
"
);
end:
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_object_release
(
p_input
);
}
/* The session may be invalid if there is a trailing \n */
char
*
psz_ln
=
strrchr
(
p_sys
->
psz_auth_token
,
'\n'
);
if
(
psz_ln
)
*
psz_ln
=
'\0'
;
static
void
HandleInterval
(
mtime_t
*
next
,
unsigned
int
*
i_interval
)
{
if
(
*
i_interval
==
0
)
{
/* first interval is 1 minute */
*
i_interval
=
1
;
}
else
{
/* else we double the previous interval, up to 120 minutes */
*
i_interval
<<=
1
;
if
(
*
i_interval
>
120
)
*
i_interval
=
120
;
if
(
!
asprintf
(
&
psz_submit
,
"s=%s"
,
p_sys
->
psz_auth_token
)
)
{
/* Out of memory */
return
;
}
/* forge the HTTP POST request */
vlc_mutex_lock
(
&
p_sys
->
lock
);
audioscrobbler_song_t
*
p_song
;
for
(
i_song
=
0
;
i_song
<
p_sys
->
i_songs
;
i_song
++
)
{
p_song
=
&
p_sys
->
p_queue
[
i_song
];
if
(
!
asprintf
(
&
psz_submit_song
,
"&a%%5B%d%%5D=%s"
"&t%%5B%d%%5D=%s"
"&i%%5B%d%%5D=%u"
"&o%%5B%d%%5D=P"
"&r%%5B%d%%5D="
"&l%%5B%d%%5D=%d"
"&b%%5B%d%%5D=%s"
"&n%%5B%d%%5D=%s"
"&m%%5B%d%%5D=%s"
,
i_song
,
p_song
->
psz_a
,
i_song
,
p_song
->
psz_t
,
i_song
,
(
unsigned
)
p_song
->
date
,
/* HACK: %ju (uintmax_t) unsupported on Windows */
i_song
,
i_song
,
i_song
,
p_song
->
i_l
,
i_song
,
p_song
->
psz_b
,
i_song
,
p_song
->
psz_n
,
i_song
,
p_song
->
psz_m
)
)
{
/* Out of memory */
vlc_mutex_unlock
(
&
p_sys
->
lock
);
return
;
}
psz_submit_tmp
=
psz_submit
;
if
(
!
asprintf
(
&
psz_submit
,
"%s%s"
,
psz_submit_tmp
,
psz_submit_song
)
)
{
/* Out of memory */
free
(
psz_submit_tmp
);
free
(
psz_submit_song
);
vlc_mutex_unlock
(
&
p_sys
->
lock
);
return
;
}
free
(
psz_submit_song
);
free
(
psz_submit_tmp
);
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
i_post_socket
=
net_ConnectTCP
(
p_intf
,
p_sys
->
psz_submit_host
,
p_sys
->
i_submit_port
);
if
(
i_post_socket
==
-
1
)
{
/* If connection fails, we assume we must handshake again */
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
p_sys
->
b_handshaked
=
false
;
free
(
psz_submit
);
continue
;
}
/* we transmit the data */
i_net_ret
=
net_Printf
(
p_intf
,
i_post_socket
,
NULL
,
POST_REQUEST
,
p_sys
->
psz_submit_file
,
(
unsigned
)
strlen
(
psz_submit
),
p_sys
->
psz_submit_host
,
VERSION
,
psz_submit
);
free
(
psz_submit
);
if
(
i_net_ret
==
-
1
)
{
/* If connection fails, we assume we must handshake again */
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
p_sys
->
b_handshaked
=
false
;
continue
;
}
i_net_ret
=
net_Read
(
p_intf
,
i_post_socket
,
NULL
,
p_buffer
,
1023
,
false
);
if
(
i_net_ret
<=
0
)
{
/* if we get no answer, something went wrong : try again */
continue
;
}
net_Close
(
i_post_socket
);
p_buffer
[
i_net_ret
]
=
'\0'
;
p_buffer_pos
=
strstr
(
(
char
*
)
p_buffer
,
"FAILED"
);
if
(
p_buffer_pos
)
{
msg_Warn
(
p_intf
,
"%s"
,
p_buffer_pos
);
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
continue
;
}
p_buffer_pos
=
strstr
(
(
char
*
)
p_buffer
,
"BADSESSION"
);
if
(
p_buffer_pos
)
{
msg_Err
(
p_intf
,
"Authentication failed (BADSESSION), are you connected to last.fm with another program ?"
);
p_sys
->
b_handshaked
=
false
;
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
continue
;
}
p_buffer_pos
=
strstr
(
(
char
*
)
p_buffer
,
"OK"
);
if
(
p_buffer_pos
)
{
int
i
;
for
(
i
=
0
;
i
<
p_sys
->
i_songs
;
i
++
)
DeleteSong
(
&
p_sys
->
p_queue
[
i
]
);
p_sys
->
i_songs
=
0
;
p_sys
->
i_interval
=
0
;
p_sys
->
next_exchange
=
mdate
();
msg_Dbg
(
p_intf
,
"Submission successful!"
);
}
else
{
msg_Err
(
p_intf
,
"Authentication failed, handshaking again (%s)"
,
p_buffer
);
p_sys
->
b_handshaked
=
false
;
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
continue
;
}
}
*
next
=
mdate
()
+
(
*
i_interval
*
1000000
*
60
);
vlc_restorecancel
(
canc
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment